feat:accessibility, new routes, cookie consent, and UI improvements
- Add contact, privacy, and terms pages - Add CookieConsent component with accept/decline and localStorage - Add self-hosted DM Sans font with @font-face definitions - Improve registration form with field validation, blur handlers, and performer toggle - Redesign Info section with 'Ongedesemd Brood' hero and FAQ layout - Remove scroll-snap behavior from all sections - Add reduced motion support and selection color theming - Add SVG favicon and SEO meta tags in root layout - Improve accessibility: aria attributes, semantic HTML, focus styles - Add link-hover underline animation utility
This commit is contained in:
@@ -8,10 +8,18 @@ import {
|
||||
Scripts,
|
||||
} from "@tanstack/react-router";
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
import { CookieConsent } from "@/components/CookieConsent";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import type { orpc } from "@/utils/orpc";
|
||||
|
||||
import appCss from "../index.css?url";
|
||||
|
||||
const siteUrl = "https://kunstenkamp.be";
|
||||
const siteTitle = "Kunstenkamp Open Mic Night - Ongedesemd Brood";
|
||||
const siteDescription =
|
||||
"Doe mee met de Open Mic Night op 18 april! Een avond vol muziek, theater, dans, woordkunst en meer. Iedereen is welkom - van beginner tot professional.";
|
||||
const eventImage = `${siteUrl}/assets/og-image.jpg`;
|
||||
|
||||
export interface RouterAppContext {
|
||||
orpc: typeof orpc;
|
||||
queryClient: QueryClient;
|
||||
@@ -28,7 +36,57 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
|
||||
content: "width=device-width, initial-scale=1",
|
||||
},
|
||||
{
|
||||
title: "My App",
|
||||
title: siteTitle,
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
content: siteDescription,
|
||||
},
|
||||
{
|
||||
name: "theme-color",
|
||||
content: "#d82560",
|
||||
},
|
||||
// Open Graph
|
||||
{
|
||||
property: "og:type",
|
||||
content: "website",
|
||||
},
|
||||
{
|
||||
property: "og:url",
|
||||
content: siteUrl,
|
||||
},
|
||||
{
|
||||
property: "og:title",
|
||||
content: siteTitle,
|
||||
},
|
||||
{
|
||||
property: "og:description",
|
||||
content: siteDescription,
|
||||
},
|
||||
{
|
||||
property: "og:image",
|
||||
content: eventImage,
|
||||
},
|
||||
{
|
||||
property: "og:locale",
|
||||
content: "nl_BE",
|
||||
},
|
||||
// Twitter Card
|
||||
{
|
||||
name: "twitter:card",
|
||||
content: "summary_large_image",
|
||||
},
|
||||
{
|
||||
name: "twitter:title",
|
||||
content: siteTitle,
|
||||
},
|
||||
{
|
||||
name: "twitter:description",
|
||||
content: siteDescription,
|
||||
},
|
||||
{
|
||||
name: "twitter:image",
|
||||
content: eventImage,
|
||||
},
|
||||
],
|
||||
links: [
|
||||
@@ -36,17 +94,58 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
|
||||
rel: "stylesheet",
|
||||
href: appCss,
|
||||
},
|
||||
{
|
||||
rel: "canonical",
|
||||
href: siteUrl,
|
||||
},
|
||||
{
|
||||
rel: "icon",
|
||||
type: "image/svg+xml",
|
||||
href: "/favicon.svg",
|
||||
},
|
||||
{
|
||||
rel: "preconnect",
|
||||
href: "https://analytics.zias.be",
|
||||
},
|
||||
],
|
||||
scripts: [
|
||||
{
|
||||
src: "https://analytics.zias.be/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js",
|
||||
defer: true,
|
||||
"data-domain": "kunstenkamp.be",
|
||||
"data-api": "https://analytics.zias.be/api/event",
|
||||
},
|
||||
{
|
||||
children:
|
||||
"window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }",
|
||||
},
|
||||
// JSON-LD Schema for Event
|
||||
{
|
||||
type: "application/ld+json",
|
||||
children: JSON.stringify({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Event",
|
||||
name: "Kunstenkamp Open Mic Night",
|
||||
description:
|
||||
"Een avond vol muziek, theater, dans, woordkunst en meer. Iedereen is welkom om zijn of haar talent te tonen.",
|
||||
startDate: "2026-04-18T19:00:00+02:00",
|
||||
eventStatus: "https://schema.org/EventScheduled",
|
||||
eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
|
||||
organizer: {
|
||||
"@type": "Organization",
|
||||
name: "Kunstenkamp",
|
||||
url: siteUrl,
|
||||
},
|
||||
image: eventImage,
|
||||
offers: {
|
||||
"@type": "Offer",
|
||||
price: "0",
|
||||
priceCurrency: "EUR",
|
||||
availability: "https://schema.org/InStock",
|
||||
validFrom: "2026-03-01T00:00:00+02:00",
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -55,13 +154,22 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
|
||||
|
||||
function RootDocument() {
|
||||
return (
|
||||
<html lang="en">
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<Outlet />
|
||||
<a
|
||||
href="#main-content"
|
||||
className="fixed top-0 left-0 z-[100] -translate-y-full bg-[#d82560] px-4 py-2 text-white transition-transform focus:translate-y-0"
|
||||
>
|
||||
Ga naar hoofdinhoud
|
||||
</a>
|
||||
<div id="main-content">
|
||||
<Outlet />
|
||||
</div>
|
||||
<Toaster />
|
||||
<CookieConsent />
|
||||
<TanStackRouterDevtools position="bottom-left" />
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
<Scripts />
|
||||
|
||||
@@ -250,9 +250,7 @@ function AdminPage() {
|
||||
className="flex items-center justify-between text-sm"
|
||||
>
|
||||
<span className="text-white/80">{item.artForm}</span>
|
||||
<span className="font-['Intro',sans-serif] text-white">
|
||||
{item.count}
|
||||
</span>
|
||||
<span className="text-white">{item.count}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
65
apps/web/src/routes/contact.tsx
Normal file
65
apps/web/src/routes/contact.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/contact")({
|
||||
component: ContactPage,
|
||||
});
|
||||
|
||||
function ContactPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#214e51]">
|
||||
<div className="mx-auto max-w-3xl px-6 py-16">
|
||||
<Link
|
||||
to="/"
|
||||
className="link-hover mb-8 inline-block text-white/80 hover:text-white"
|
||||
>
|
||||
← Terug naar home
|
||||
</Link>
|
||||
<h1 className="mb-8 font-['Intro',sans-serif] text-4xl text-white">
|
||||
Contact
|
||||
</h1>
|
||||
|
||||
<div className="space-y-6 text-white/80">
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Heb je vragen?</h2>
|
||||
<p className="mb-4">
|
||||
We helpen je graag! Je kunt ons bereiken via de volgende kanalen:
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="rounded-lg bg-white/5 p-6">
|
||||
<h3 className="mb-3 text-white text-xl">E-mail</h3>
|
||||
<a
|
||||
href="mailto:info@kunstenkamp.be"
|
||||
className="link-hover text-white/80 hover:text-white"
|
||||
>
|
||||
info@kunstenkamp.be
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section className="rounded-lg bg-white/5 p-6">
|
||||
<h3 className="mb-3 text-white text-xl">Open Mic Night</h3>
|
||||
<p>Vrijdag 18 april 2026</p>
|
||||
<p>Aanvang: 19:00 uur</p>
|
||||
<p className="mt-2 text-white/60">
|
||||
Locatie wordt later bekendgemaakt aan geregistreerde deelnemers.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="rounded-lg bg-white/5 p-6">
|
||||
<h3 className="mb-3 text-white text-xl">Organisatie</h3>
|
||||
<p>Kunstenkamp vzw</p>
|
||||
<p className="mt-2 text-white/60">
|
||||
Een initiatief voor en door kunstenaars.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="mt-8">
|
||||
<p className="text-sm text-white/60">
|
||||
We proberen je e-mail binnen 48 uur te beantwoorden.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -116,7 +116,7 @@ function LoginPage() {
|
||||
};
|
||||
|
||||
const handleRequestAdmin = () => {
|
||||
requestAdminMutation.mutate();
|
||||
requestAdminMutation.mutate(undefined);
|
||||
};
|
||||
|
||||
// If already logged in as admin, redirect
|
||||
|
||||
75
apps/web/src/routes/privacy.tsx
Normal file
75
apps/web/src/routes/privacy.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/privacy")({
|
||||
component: PrivacyPage,
|
||||
});
|
||||
|
||||
function PrivacyPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#214e51]">
|
||||
<div className="mx-auto max-w-3xl px-6 py-16">
|
||||
<Link
|
||||
to="/"
|
||||
className="link-hover mb-8 inline-block text-white/80 hover:text-white"
|
||||
>
|
||||
← Terug naar home
|
||||
</Link>
|
||||
<h1 className="mb-8 font-['Intro',sans-serif] text-4xl text-white">
|
||||
Privacybeleid
|
||||
</h1>
|
||||
|
||||
<div className="space-y-6 text-white/80">
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">
|
||||
Welke gegevens verzamelen we?
|
||||
</h2>
|
||||
<p>
|
||||
We verzamelen alleen de gegevens die je zelf invoert bij de
|
||||
registratie: voornaam, achternaam, e-mailadres, telefoonnummer,
|
||||
kunstvorm en ervaring.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">
|
||||
Waarom verzamelen we deze gegevens?
|
||||
</h2>
|
||||
<p>
|
||||
We gebruiken je gegevens om je te kunnen contacteren over de Open
|
||||
Mic Night, om het programma samen te stellen en om je te
|
||||
informeren over aanvullende details over het evenement.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">
|
||||
Hoe lang bewaren we je gegevens?
|
||||
</h2>
|
||||
<p>
|
||||
Je gegevens worden bewaard tot na het evenement en maximaal 6
|
||||
maanden daarna, tenzij je vraagt om eerder verwijdering.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Je rechten</h2>
|
||||
<p>
|
||||
Je hebt het recht om je gegevens in te zien, te corrigeren of te
|
||||
laten verwijderen. Neem hiervoor contact op via
|
||||
info@kunstenkamp.be.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Cookies</h2>
|
||||
<p>
|
||||
We gebruiken alleen analytische cookies om het gebruik van onze
|
||||
website te verbeteren. Deze cookies bevatten geen persoonlijke
|
||||
informatie.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
71
apps/web/src/routes/terms.tsx
Normal file
71
apps/web/src/routes/terms.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/terms")({
|
||||
component: TermsPage,
|
||||
});
|
||||
|
||||
function TermsPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#214e51]">
|
||||
<div className="mx-auto max-w-3xl px-6 py-16">
|
||||
<Link
|
||||
to="/"
|
||||
className="link-hover mb-8 inline-block text-white/80 hover:text-white"
|
||||
>
|
||||
← Terug naar home
|
||||
</Link>
|
||||
<h1 className="mb-8 font-['Intro',sans-serif] text-4xl text-white">
|
||||
Algemene Voorwaarden
|
||||
</h1>
|
||||
|
||||
<div className="space-y-6 text-white/80">
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">
|
||||
Deelname aan Open Mic Night
|
||||
</h2>
|
||||
<p>
|
||||
Door je te registreren voor de Open Mic Night ga je akkoord met
|
||||
deze voorwaarden. Je krijgt 5-7 minuten podiumtijd, afhankelijk
|
||||
van het aantal deelnemers.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Annulering</h2>
|
||||
<p>
|
||||
Als je niet kunt komen, geef dit dan minimaal 48 uur van tevoren
|
||||
door. Zo kunnen we iemand anders de kans geven om op te treden.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Gedragsregels</h2>
|
||||
<p>
|
||||
We verwachten van alle deelnemers dat ze respectvol omgaan met
|
||||
elkaar, het publiek en het materiaal. Discriminatie, intimidatie
|
||||
of agressief gedrag worden niet getolereerd.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Foto's en video's</h2>
|
||||
<p>
|
||||
Tijdens het evenement kunnen foto's en video's worden gemaakt voor
|
||||
promotionele doeleinden. Door deel te nemen ga je hiermee akkoord,
|
||||
tenziij je dit expliciet aangeeft bij de organisatie.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="mb-3 text-2xl text-white">Aansprakelijkheid</h2>
|
||||
<p>
|
||||
Kunstenkamp is niet aansprakelijk voor verlies of beschadiging van
|
||||
persoonlijke eigendommen. Je bent zelf verantwoordelijk voor je
|
||||
eigen materiaal en instrumenten.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user