feat: kamp page
This commit is contained in:
@@ -8,7 +8,10 @@ import { Header } from "./Header";
|
||||
export function SiteHeader() {
|
||||
const { data: session } = authClient.useSession();
|
||||
const routerState = useRouterState();
|
||||
const isHomepage = routerState.location.pathname === "/";
|
||||
const pathname = routerState.location.pathname;
|
||||
const isHomepage = pathname === "/";
|
||||
|
||||
if (pathname === "/kamp") return null;
|
||||
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ 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 KampRouteImport } from './routes/kamp'
|
||||
import { Route as ForgotPasswordRouteImport } from './routes/forgot-password'
|
||||
import { Route as DrinkkaartRouteImport } from './routes/drinkkaart'
|
||||
import { Route as ContactRouteImport } from './routes/contact'
|
||||
@@ -42,16 +42,16 @@ 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',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const KampRoute = KampRouteImport.update({
|
||||
id: '/kamp',
|
||||
path: '/kamp',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const ForgotPasswordRoute = ForgotPasswordRouteImport.update({
|
||||
id: '/forgot-password',
|
||||
path: '/forgot-password',
|
||||
@@ -119,8 +119,8 @@ export interface FileRoutesByFullPath {
|
||||
'/contact': typeof ContactRoute
|
||||
'/drinkkaart': typeof DrinkkaartRoute
|
||||
'/forgot-password': typeof ForgotPasswordRoute
|
||||
'/kamp': typeof KampRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/open-mic': typeof OpenMicRoute
|
||||
'/privacy': typeof PrivacyRoute
|
||||
'/reset-password': typeof ResetPasswordRoute
|
||||
'/terms': typeof TermsRoute
|
||||
@@ -138,8 +138,8 @@ export interface FileRoutesByTo {
|
||||
'/contact': typeof ContactRoute
|
||||
'/drinkkaart': typeof DrinkkaartRoute
|
||||
'/forgot-password': typeof ForgotPasswordRoute
|
||||
'/kamp': typeof KampRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/open-mic': typeof OpenMicRoute
|
||||
'/privacy': typeof PrivacyRoute
|
||||
'/reset-password': typeof ResetPasswordRoute
|
||||
'/terms': typeof TermsRoute
|
||||
@@ -158,8 +158,8 @@ export interface FileRoutesById {
|
||||
'/contact': typeof ContactRoute
|
||||
'/drinkkaart': typeof DrinkkaartRoute
|
||||
'/forgot-password': typeof ForgotPasswordRoute
|
||||
'/kamp': typeof KampRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/open-mic': typeof OpenMicRoute
|
||||
'/privacy': typeof PrivacyRoute
|
||||
'/reset-password': typeof ResetPasswordRoute
|
||||
'/terms': typeof TermsRoute
|
||||
@@ -179,8 +179,8 @@ export interface FileRouteTypes {
|
||||
| '/contact'
|
||||
| '/drinkkaart'
|
||||
| '/forgot-password'
|
||||
| '/kamp'
|
||||
| '/login'
|
||||
| '/open-mic'
|
||||
| '/privacy'
|
||||
| '/reset-password'
|
||||
| '/terms'
|
||||
@@ -198,8 +198,8 @@ export interface FileRouteTypes {
|
||||
| '/contact'
|
||||
| '/drinkkaart'
|
||||
| '/forgot-password'
|
||||
| '/kamp'
|
||||
| '/login'
|
||||
| '/open-mic'
|
||||
| '/privacy'
|
||||
| '/reset-password'
|
||||
| '/terms'
|
||||
@@ -217,8 +217,8 @@ export interface FileRouteTypes {
|
||||
| '/contact'
|
||||
| '/drinkkaart'
|
||||
| '/forgot-password'
|
||||
| '/kamp'
|
||||
| '/login'
|
||||
| '/open-mic'
|
||||
| '/privacy'
|
||||
| '/reset-password'
|
||||
| '/terms'
|
||||
@@ -237,8 +237,8 @@ export interface RootRouteChildren {
|
||||
ContactRoute: typeof ContactRoute
|
||||
DrinkkaartRoute: typeof DrinkkaartRoute
|
||||
ForgotPasswordRoute: typeof ForgotPasswordRoute
|
||||
KampRoute: typeof KampRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OpenMicRoute: typeof OpenMicRoute
|
||||
PrivacyRoute: typeof PrivacyRoute
|
||||
ResetPasswordRoute: typeof ResetPasswordRoute
|
||||
TermsRoute: typeof TermsRoute
|
||||
@@ -274,13 +274,6 @@ 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'
|
||||
@@ -288,6 +281,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof LoginRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/kamp': {
|
||||
id: '/kamp'
|
||||
path: '/kamp'
|
||||
fullPath: '/kamp'
|
||||
preLoaderRoute: typeof KampRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/forgot-password': {
|
||||
id: '/forgot-password'
|
||||
path: '/forgot-password'
|
||||
@@ -381,8 +381,8 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
ContactRoute: ContactRoute,
|
||||
DrinkkaartRoute: DrinkkaartRoute,
|
||||
ForgotPasswordRoute: ForgotPasswordRoute,
|
||||
KampRoute: KampRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OpenMicRoute: OpenMicRoute,
|
||||
PrivacyRoute: PrivacyRoute,
|
||||
ResetPasswordRoute: ResetPasswordRoute,
|
||||
TermsRoute: TermsRoute,
|
||||
|
||||
@@ -1,318 +1,168 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { useEffect, useState } from "react";
|
||||
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";
|
||||
|
||||
const KAMP_BANNER_KEY = "kk_kamp_banner_dismissed";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: SelectorPage,
|
||||
component: HomePage,
|
||||
});
|
||||
|
||||
function SelectorPage() {
|
||||
const [hovered, setHovered] = useState<"kamp" | "openmic" | null>(null);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
function KampBanner({ onDismiss }: { onDismiss: () => void }) {
|
||||
const [visible, setVisible] = 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);
|
||||
if (!document.getElementById("kamp-banner-font")) {
|
||||
const el = document.createElement("link");
|
||||
el.id = "kamp-banner-font";
|
||||
el.rel = "stylesheet";
|
||||
el.href =
|
||||
"https://fonts.googleapis.com/css2?family=Special+Elite&display=swap";
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
const t = setTimeout(() => setVisible(true), 600);
|
||||
return () => clearTimeout(t);
|
||||
}, []);
|
||||
|
||||
const handleDismiss = () => {
|
||||
setVisible(false);
|
||||
setTimeout(onDismiss, 300);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex h-[100dvh] w-full flex-col sm:flex-row"
|
||||
style={{ gap: "6px", background: "#0a0a0a" }}
|
||||
role="banner"
|
||||
aria-label="Kunstenkamp inschrijvingen"
|
||||
style={{
|
||||
position: "fixed",
|
||||
bottom: "1.25rem",
|
||||
left: "50%",
|
||||
transform: visible
|
||||
? "translateX(-50%) translateY(0)"
|
||||
: "translateX(-50%) translateY(120%)",
|
||||
transition: "transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1)",
|
||||
zIndex: 50,
|
||||
width: "min(calc(100vw - 2rem), 480px)",
|
||||
}}
|
||||
>
|
||||
{/* ── 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"
|
||||
<div
|
||||
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",
|
||||
background: "#ede4c8",
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E")`,
|
||||
border: "1px solid #12100e",
|
||||
outline: "3px solid rgba(18,16,14,0.1)",
|
||||
outlineOffset: "3px",
|
||||
borderRadius: 0,
|
||||
padding: "12px 14px 14px",
|
||||
boxShadow: "3px 5px 20px rgba(0,0,0,0.25)",
|
||||
}}
|
||||
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)",
|
||||
}}
|
||||
/>
|
||||
{/* Top double rule */}
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<div style={{ height: "2px", background: "#12100e", marginBottom: "3px" }} />
|
||||
<div style={{ height: "1px", background: "rgba(18,16,14,0.35)" }} />
|
||||
</div>
|
||||
|
||||
{/* 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 */}
|
||||
<div style={{ display: "flex", alignItems: "flex-start", gap: "10px" }}>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<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",
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "8px",
|
||||
letterSpacing: "0.3em",
|
||||
textTransform: "uppercase",
|
||||
color: "rgba(18,16,14,0.45)",
|
||||
marginBottom: "6px",
|
||||
}}
|
||||
>
|
||||
Kunstenkamp
|
||||
✦ Aankondiging · Zomerkamp 2026 ✦
|
||||
</p>
|
||||
|
||||
<h2
|
||||
className="font-['Intro',sans-serif] text-white uppercase leading-[0.88]"
|
||||
<p
|
||||
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",
|
||||
fontFamily: "'Playfair Display', serif",
|
||||
fontWeight: 700,
|
||||
fontSize: "14px",
|
||||
color: "#12100e",
|
||||
lineHeight: 1.35,
|
||||
marginBottom: "12px",
|
||||
}}
|
||||
>
|
||||
<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
|
||||
Inschrijvingen voor de zomerkampen zijn open!
|
||||
</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"
|
||||
to="/kamp"
|
||||
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",
|
||||
display: "inline-block",
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "9px",
|
||||
letterSpacing: "0.22em",
|
||||
textTransform: "uppercase",
|
||||
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",
|
||||
color: "#ede4c8",
|
||||
background: "#12100e",
|
||||
border: "1px solid rgba(18,16,14,0.4)",
|
||||
outline: "2px solid rgba(18,16,14,0.08)",
|
||||
outlineOffset: "3px",
|
||||
padding: "7px 12px 6px",
|
||||
}}
|
||||
>
|
||||
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>
|
||||
Schrijf je in →
|
||||
</Link>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDismiss}
|
||||
aria-label="Sluit deze melding"
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
color: "rgba(18,16,14,0.3)",
|
||||
cursor: "pointer",
|
||||
padding: "2px",
|
||||
flexShrink: 0,
|
||||
fontSize: "18px",
|
||||
lineHeight: 1,
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function HomePage() {
|
||||
const [showBanner, setShowBanner] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!localStorage.getItem(KAMP_BANNER_KEY)) {
|
||||
setShowBanner(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const dismissBanner = () => {
|
||||
localStorage.setItem(KAMP_BANNER_KEY, "1");
|
||||
setShowBanner(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative">
|
||||
<main className="relative">
|
||||
<Hero />
|
||||
<Info />
|
||||
<HoeInschrijven />
|
||||
<EventRegistrationForm />
|
||||
<Footer />
|
||||
</main>
|
||||
</div>
|
||||
{showBanner && <KampBanner onDismiss={dismissBanner} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
474
apps/web/src/routes/kamp.tsx
Normal file
474
apps/web/src/routes/kamp.tsx
Normal file
@@ -0,0 +1,474 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const KAMP_URL = "https://ejv.be/jong/kampen/kunstenkamp/";
|
||||
|
||||
export const Route = createFileRoute("/kamp")({
|
||||
component: KampPage,
|
||||
});
|
||||
|
||||
const STYLES = `
|
||||
@import url('https://fonts.googleapis.com/css2?family=UnifrakturMaguntia&family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700&family=EB+Garamond:ital,wght@0,400;0,500;1,400;1,500&family=Special+Elite&display=swap');
|
||||
|
||||
@keyframes kampPressIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
body.kamp-page {
|
||||
background-color: #d6cdb0 !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.kamp-page ::selection {
|
||||
background: #12100e;
|
||||
color: #ede4c8;
|
||||
}
|
||||
|
||||
.kamp-scroll::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
.kamp-scroll::-webkit-scrollbar-track {
|
||||
background: #c9c0a4;
|
||||
}
|
||||
.kamp-scroll::-webkit-scrollbar-thumb {
|
||||
background: #12100e;
|
||||
}
|
||||
`;
|
||||
|
||||
const PAPER = "#ede4c8";
|
||||
const INK = "#12100e";
|
||||
const INK_MID = "rgba(18,16,14,0.5)";
|
||||
const INK_GHOST = "rgba(18,16,14,0.2)";
|
||||
const RULE_W = "rgba(18,16,14,0.75)";
|
||||
|
||||
function TripleRule() {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "3px" }}>
|
||||
<div style={{ height: "3px", background: INK }} />
|
||||
<div style={{ height: "1px", background: RULE_W }} />
|
||||
<div style={{ height: "2px", background: INK }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DoubleRule() {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "3px" }}>
|
||||
<div style={{ height: "2px", background: RULE_W }} />
|
||||
<div style={{ height: "1px", background: RULE_W }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function KampPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [ctaHovered, setCtaHovered] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!document.getElementById("kamp-newspaper-styles")) {
|
||||
const el = document.createElement("style");
|
||||
el.id = "kamp-newspaper-styles";
|
||||
el.textContent = STYLES;
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
document.body.classList.add("kamp-page");
|
||||
const t = setTimeout(() => setMounted(true), 60);
|
||||
return () => {
|
||||
document.body.classList.remove("kamp-page");
|
||||
clearTimeout(t);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "100dvh",
|
||||
background: "#d6cdb0",
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='400' height='400' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E")`,
|
||||
backgroundRepeat: "repeat",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "1.5rem 1rem",
|
||||
}}
|
||||
>
|
||||
{/* Newspaper page */}
|
||||
<article
|
||||
className="kamp-scroll"
|
||||
style={{
|
||||
width: "100%",
|
||||
maxWidth: "700px",
|
||||
height: "100%",
|
||||
background: PAPER,
|
||||
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E")`,
|
||||
border: `1px solid ${INK}`,
|
||||
boxShadow:
|
||||
"3px 5px 24px rgba(0,0,0,0.18), 0 1px 3px rgba(0,0,0,0.12)",
|
||||
opacity: mounted ? 1 : 0,
|
||||
animation: mounted ? "kampPressIn 0.9s ease both" : undefined,
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
{/* Outer decorative border inset */}
|
||||
<div
|
||||
style={{
|
||||
margin: "6px",
|
||||
border: `1px solid ${INK}`,
|
||||
}}
|
||||
>
|
||||
{/* Top flag strip */}
|
||||
<div
|
||||
style={{
|
||||
borderBottom: `1px solid ${INK}`,
|
||||
padding: "7px 20px 6px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to="/"
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "10px",
|
||||
letterSpacing: "0.18em",
|
||||
color: INK,
|
||||
textDecoration: "none",
|
||||
borderBottom: `1px solid ${INK}`,
|
||||
paddingBottom: "1px",
|
||||
}}
|
||||
>
|
||||
← Open Mic Night
|
||||
</Link>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "9px",
|
||||
letterSpacing: "0.18em",
|
||||
color: INK_MID,
|
||||
}}
|
||||
>
|
||||
✦ · ✦ · ✦
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "9px",
|
||||
letterSpacing: "0.22em",
|
||||
textTransform: "uppercase",
|
||||
color: INK_MID,
|
||||
}}
|
||||
>
|
||||
Anno 2026
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Masthead */}
|
||||
<div
|
||||
style={{
|
||||
padding: "20px 24px 16px",
|
||||
textAlign: "center",
|
||||
borderBottom: `1px solid ${INK}`,
|
||||
}}
|
||||
>
|
||||
<h1
|
||||
style={{
|
||||
fontFamily: "'UnifrakturMaguntia', cursive",
|
||||
fontSize: "clamp(2.4rem, 9vw, 4.5rem)",
|
||||
color: INK,
|
||||
margin: 0,
|
||||
lineHeight: 1,
|
||||
letterSpacing: "0.02em",
|
||||
}}
|
||||
>
|
||||
De Kunstenkamp Gazet
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Publication bar */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
padding: "6px 20px 5px",
|
||||
borderBottom: `1px solid ${INK}`,
|
||||
}}
|
||||
>
|
||||
{[
|
||||
"Vol. CCXXVI",
|
||||
"Zomerkamp · Juli 2026",
|
||||
"Prijs: uw aanwezigheid",
|
||||
].map((t) => (
|
||||
<span
|
||||
key={t}
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "10px",
|
||||
color: INK_MID,
|
||||
letterSpacing: "0.1em",
|
||||
}}
|
||||
>
|
||||
{t}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main content area */}
|
||||
<div style={{ padding: "28px 28px 24px" }}>
|
||||
{/* Triple rule */}
|
||||
<div style={{ marginBottom: "24px" }}>
|
||||
<TripleRule />
|
||||
</div>
|
||||
|
||||
{/* Main headline */}
|
||||
<div style={{ textAlign: "center", marginBottom: "16px" }}>
|
||||
<h2
|
||||
style={{
|
||||
fontFamily: "'Playfair Display', serif",
|
||||
fontWeight: 900,
|
||||
fontSize: "clamp(2.6rem, 9vw, 4.5rem)",
|
||||
color: INK,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "0.06em",
|
||||
lineHeight: 0.95,
|
||||
margin: "0 0 14px",
|
||||
}}
|
||||
>
|
||||
Wat Is Waar?
|
||||
</h2>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'Playfair Display', serif",
|
||||
fontStyle: "italic",
|
||||
fontSize: "clamp(1rem, 2.5vw, 1.2rem)",
|
||||
color: INK_MID,
|
||||
margin: 0,
|
||||
lineHeight: 1.45,
|
||||
}}
|
||||
>
|
||||
Een krant. Een tijdmachine. De waarheid doorheen de eeuwen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Triple rule */}
|
||||
<div style={{ marginBottom: "22px" }}>
|
||||
<TripleRule />
|
||||
</div>
|
||||
|
||||
{/* Editorial body copy */}
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'EB Garamond', serif",
|
||||
fontSize: "clamp(1.05rem, 2.2vw, 1.2rem)",
|
||||
color: INK,
|
||||
lineHeight: 1.75,
|
||||
margin: "0 0 10px",
|
||||
textAlign: "justify",
|
||||
hyphens: "auto",
|
||||
}}
|
||||
>
|
||||
In de zomer van 1826 — en opnieuw in 2026 — reizen onze verslaggevers
|
||||
terug naar de roerige redactiezalen van de negentiende eeuw. Waar de
|
||||
drukpers ronkt, de rookmachines tieren en elke kop een mening
|
||||
verbergt, stellen wij de vraag die door alle eeuwen galmt:{" "}
|
||||
<em>wat mogen wij geloven?</em>
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'EB Garamond', serif",
|
||||
fontStyle: "italic",
|
||||
fontSize: "clamp(0.95rem, 2vw, 1.08rem)",
|
||||
color: INK_MID,
|
||||
lineHeight: 1.7,
|
||||
margin: "0 0 24px",
|
||||
textAlign: "justify",
|
||||
hyphens: "auto",
|
||||
}}
|
||||
>
|
||||
Twee waarheden en een leugen. Vier bolhoeden en één typmachine.
|
||||
Bereid u voor op een week journalistiek, theater, dans en woordkunst
|
||||
— alles gehuld in inkt en papier-maché.
|
||||
</p>
|
||||
|
||||
{/* Ornamental divider */}
|
||||
<p
|
||||
style={{
|
||||
textAlign: "center",
|
||||
fontFamily: "'EB Garamond', serif",
|
||||
fontSize: "13px",
|
||||
color: INK_GHOST,
|
||||
margin: "0 0 24px",
|
||||
letterSpacing: "0.4em",
|
||||
}}
|
||||
>
|
||||
— ✦ · ✦ · ✦ —
|
||||
</p>
|
||||
|
||||
{/* Details grid */}
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
border: `1px solid ${INK}`,
|
||||
marginBottom: "28px",
|
||||
}}
|
||||
>
|
||||
{[
|
||||
{ label: "Primo", value: "20 – 25 Juli 2026" },
|
||||
{ label: "Secundo", value: "27 Juli – 1 Aug 2026" },
|
||||
{
|
||||
label: "Leeftijd",
|
||||
value: "9 – 18 jaar",
|
||||
sub: "* geboortejaar dat je 10 wordt",
|
||||
},
|
||||
{
|
||||
label: "Locatie",
|
||||
value: "Camp de Limauges",
|
||||
sub: "Ceroux-Mousty · België",
|
||||
},
|
||||
].map(({ label, value, sub }, i) => (
|
||||
<div
|
||||
key={label}
|
||||
style={{
|
||||
padding: "16px 18px",
|
||||
borderRight:
|
||||
i % 2 === 0 ? `1px solid ${INK}` : undefined,
|
||||
borderTop: i >= 2 ? `1px solid ${INK}` : undefined,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "9px",
|
||||
letterSpacing: "0.3em",
|
||||
textTransform: "uppercase",
|
||||
color: INK_MID,
|
||||
margin: "0 0 6px",
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'Playfair Display', serif",
|
||||
fontWeight: 700,
|
||||
fontSize: "clamp(1rem, 2.5vw, 1.15rem)",
|
||||
color: INK,
|
||||
margin: 0,
|
||||
lineHeight: 1.3,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</p>
|
||||
{sub && (
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'EB Garamond', serif",
|
||||
fontStyle: "italic",
|
||||
fontSize: "13px",
|
||||
color: INK_MID,
|
||||
margin: "4px 0 0",
|
||||
}}
|
||||
>
|
||||
{sub}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Double rule */}
|
||||
<div style={{ marginBottom: "24px" }}>
|
||||
<DoubleRule />
|
||||
</div>
|
||||
|
||||
{/* CTA — inverted ink block */}
|
||||
<div style={{ marginBottom: "4px" }}>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "9px",
|
||||
letterSpacing: "0.35em",
|
||||
textTransform: "uppercase",
|
||||
color: INK_MID,
|
||||
textAlign: "center",
|
||||
margin: "0 0 10px",
|
||||
}}
|
||||
>
|
||||
✦ Aankondiging ✦
|
||||
</p>
|
||||
|
||||
<a
|
||||
href={KAMP_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onMouseEnter={() => setCtaHovered(true)}
|
||||
onMouseLeave={() => setCtaHovered(false)}
|
||||
style={{
|
||||
display: "block",
|
||||
background: ctaHovered ? "#2a2418" : INK,
|
||||
color: PAPER,
|
||||
textDecoration: "none",
|
||||
textAlign: "center",
|
||||
padding: "28px 32px 26px",
|
||||
outline: `2px solid ${INK}`,
|
||||
outlineOffset: "4px",
|
||||
transition: "background 0.2s ease",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
display: "block",
|
||||
fontFamily: "'Playfair Display', serif",
|
||||
fontWeight: 900,
|
||||
fontSize: "clamp(1.5rem, 5vw, 2.4rem)",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "0.1em",
|
||||
lineHeight: 1,
|
||||
marginBottom: "10px",
|
||||
}}
|
||||
>
|
||||
Schrijf U In
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
display: "block",
|
||||
fontFamily: "'Special Elite', cursive",
|
||||
fontSize: "clamp(0.7rem, 2vw, 0.85rem)",
|
||||
letterSpacing: "0.25em",
|
||||
opacity: 0.65,
|
||||
}}
|
||||
>
|
||||
via ejv.be →
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div
|
||||
style={{
|
||||
borderTop: `1px solid ${INK}`,
|
||||
padding: "7px 20px 8px",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "'EB Garamond', serif",
|
||||
fontStyle: "italic",
|
||||
fontSize: "12px",
|
||||
color: INK_GHOST,
|
||||
margin: 0,
|
||||
letterSpacing: "0.06em",
|
||||
}}
|
||||
>
|
||||
Kunst · Expressie · Avontuur · Waar is de waarheid?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
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