feat: Mollie betaalflow, inschrijfpagina, SEO en deploy
Betaalflow via Tally formulier (e-mailverzameling) + Mollie Payment Links. Inschrijfpagina (/inschrijven), bedankt-pagina (/bedankt), OpenGraph tags, favicon, Umami analytics, base path config en deploy script toegevoegd. Site live op frankmeeuwsen.com/workshopclaudecode/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
13eca07719
commit
e791e06f1d
16 changed files with 347 additions and 25 deletions
41
LOGBOEK.md
41
LOGBOEK.md
|
|
@ -66,7 +66,40 @@
|
|||
- Workshop details (datum/tijd/locatie) compact weergegeven met iconen
|
||||
|
||||
### Volgende sessie
|
||||
- [ ] Inschrijfformulier/betaallink toevoegen
|
||||
- [ ] Deploy naar productie
|
||||
- [ ] SEO meta tags toevoegen (Open Graph, Twitter Cards)
|
||||
- [ ] Formulier validatie en betalingsflow
|
||||
- [x] Inschrijfformulier/betaallink toevoegen
|
||||
- [x] Deploy naar productie
|
||||
- [x] SEO meta tags toevoegen (Open Graph, Twitter Cards)
|
||||
- [x] Formulier validatie en betalingsflow
|
||||
|
||||
## 2026-02-10 - Sessie 4: Mollie betaalflow, SEO en deploy
|
||||
|
||||
### Wat is gebouwd
|
||||
- Mollie Payment Links aangemaakt (test + live) voor workshop betaling
|
||||
- Tally formulier geintegreerd voor e-mailverzameling voor inschrijving
|
||||
- Inschrijfpagina (/inschrijven) met embedded Tally formulier
|
||||
- Bedankt-pagina (/bedankt) voor na succesvolle betaling
|
||||
- Payment config bestand (src/config/payment.js) voor centrale URL configuratie
|
||||
- CTA-knoppen (Pricing, FinalCTA, StickyBar) gelinkt naar inschrijfpagina via React Router Link
|
||||
- Hero CTA scrollt nog steeds naar pricing sectie
|
||||
- OpenGraph en Twitter Card meta tags in index.html
|
||||
- OG-afbeelding (1200x630) gemaakt in Canva met site-kleuren en headline
|
||||
- SVG favicon (coral CC icoon)
|
||||
- Umami analytics script toegevoegd (zelfde ID als frankmeeuwsen.com)
|
||||
- Canonical URL ingesteld
|
||||
- Base path config (/workshopclaudecode/) alleen voor production builds
|
||||
- .htaccess voor SPA-routing in submap
|
||||
- Deploy script (deploy.sh) voor build + upload naar Coolify Docker container
|
||||
- Site live gedeployd op https://frankmeeuwsen.com/workshopclaudecode/
|
||||
|
||||
### Technische beslissingen
|
||||
- Tally als tussenstap voor e-mailverzameling (geen backend nodig, AVG-compliant, gratis)
|
||||
- Betaalflow: CTA -> /inschrijven (Tally embed) -> Mollie betaalpagina -> /bedankt
|
||||
- Vite base path conditioneel: / voor dev, /workshopclaudecode/ voor build
|
||||
- React Router basename via import.meta.env.BASE_URL (werkt automatisch in beide modes)
|
||||
- Hero afbeelding pad via import.meta.env.BASE_URL voor correcte submap-verwijzing
|
||||
- Deploy via rsync + docker cp naar WordPress container op Coolify
|
||||
|
||||
### Volgende sessie
|
||||
- [ ] Testimonials toevoegen zodra beschikbaar
|
||||
- [ ] Structured data (JSON-LD Event schema) toevoegen
|
||||
- [ ] Eerste testbetaling via live link verifiëren
|
||||
|
|
|
|||
BIN
content/Social image CC workshop.png
Normal file
BIN
content/Social image CC workshop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 674 KiB |
26
deploy.sh
Executable file
26
deploy.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
# Deploy script voor Claude Code Workshop sales page
|
||||
# Bouwt de site en deployt naar de Coolify WordPress container
|
||||
#
|
||||
# Gebruik: ./deploy.sh
|
||||
|
||||
set -e
|
||||
|
||||
SERVER="coolify"
|
||||
CONTAINER="wordpress-d0wko4gskokosssogcw8040g"
|
||||
REMOTE_PATH="/var/www/html/workshopclaudecode"
|
||||
TMP_PATH="/tmp/workshopclaudecode"
|
||||
|
||||
echo "1/4 - Building..."
|
||||
npm run build --silent
|
||||
|
||||
echo "2/4 - Uploading naar server..."
|
||||
rsync -avz --quiet dist/ "$SERVER:$TMP_PATH/"
|
||||
|
||||
echo "3/4 - Kopieren naar container..."
|
||||
ssh "$SERVER" "docker cp $TMP_PATH/. $CONTAINER:$REMOTE_PATH/ && docker exec $CONTAINER chown -R www-data:www-data $REMOTE_PATH/"
|
||||
|
||||
echo "4/4 - Opruimen..."
|
||||
ssh "$SERVER" "rm -rf $TMP_PATH"
|
||||
|
||||
echo "Done! https://frankmeeuwsen.com/workshopclaudecode/"
|
||||
25
index.html
25
index.html
|
|
@ -2,11 +2,34 @@
|
|||
<html lang="nl">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Claude Code Workshop - Van nieuwsgierig naar praktisch aan de slag</title>
|
||||
<meta name="description" content="Leer Claude Code in 1 ochtend. Van installatie tot werkende applicaties. Kleine groep, hands-on, 6 maart 2026 in Utrecht." />
|
||||
|
||||
<!-- Canonical -->
|
||||
<link rel="canonical" href="https://frankmeeuwsen.com/workshopclaudecode/" />
|
||||
|
||||
<!-- OpenGraph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:locale" content="nl_NL" />
|
||||
<meta property="og:title" content="Claude Code Workshop - Maak zelf de tools die je nu inhuurt" />
|
||||
<meta property="og:description" content="In 1 ochtend van nieuwsgierig naar praktisch aan de slag met Claude Code. Kleine groep, hands-on. 6 maart 2026 in Utrecht." />
|
||||
<meta property="og:url" content="https://frankmeeuwsen.com/workshopclaudecode/" />
|
||||
<meta property="og:image" content="https://frankmeeuwsen.com/workshopclaudecode/og-image.png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:site_name" content="Frank Meeuwsen" />
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Claude Code Workshop - Maak zelf de tools die je nu inhuurt" />
|
||||
<meta name="twitter:description" content="In 1 ochtend van nieuwsgierig naar praktisch aan de slag met Claude Code. Kleine groep, hands-on. 6 maart 2026 in Utrecht." />
|
||||
<meta name="twitter:image" content="https://frankmeeuwsen.com/workshopclaudecode/og-image.png" />
|
||||
|
||||
<!-- Umami Analytics -->
|
||||
<script defer src="https://umami.dutchstack.nl/script.js" data-website-id="bceaa80a-f2be-4215-8421-3a78d14601c3"></script>
|
||||
|
||||
<!-- Google Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
|
|
|||
13
public/.htaccess
Normal file
13
public/.htaccess
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# SPA routing: stuur alle requests naar index.html
|
||||
# zodat React Router de routes /bedankt, /inschrijven etc. kan afhandelen
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /workshopclaudecode/
|
||||
|
||||
# Als het bestand of directory bestaat, serveer het direct
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
# Alles anders naar index.html
|
||||
RewriteRule ^ index.html [QSA,L]
|
||||
</IfModule>
|
||||
4
public/favicon.svg
Normal file
4
public/favicon.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="6" fill="#F25C3D"/>
|
||||
<text x="16" y="22" font-family="system-ui, sans-serif" font-weight="700" font-size="18" fill="white" text-anchor="middle">CC</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 257 B |
BIN
public/og-image.png
Normal file
BIN
public/og-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 674 KiB |
|
|
@ -2,9 +2,12 @@
|
|||
* FinalCTA.jsx - Afsluitende call-to-action sectie
|
||||
*
|
||||
* Coral-500 achtergrond met witte tekst.
|
||||
* Bevat datum, locatie en primaire CTA button (wit met coral tekst).
|
||||
* Bevat datum, locatie en CTA button die naar Mollie betaalpagina linkt.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { PAYMENT_CONFIG } from '../config/payment';
|
||||
|
||||
function FinalCTA() {
|
||||
return (
|
||||
<section className="py-16 lg:py-24 bg-coral-500 relative overflow-hidden">
|
||||
|
|
@ -55,16 +58,16 @@ function FinalCTA() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button - wit met coral tekst */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
{/* CTA Button - naar inschrijfpagina */}
|
||||
<Link
|
||||
to={PAYMENT_CONFIG.SIGNUP_URL}
|
||||
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-coral-600 font-semibold text-lg rounded-xl shadow-lg hover:bg-coral-50 hover:shadow-xl active:bg-coral-100 transition-all duration-200"
|
||||
>
|
||||
Doe mee op 6 maart
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
{/* Contact info */}
|
||||
<p className="mt-8 text-coral-200">
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ function Hero() {
|
|||
<div className="hidden lg:block">
|
||||
<div className="relative">
|
||||
<img
|
||||
src="/frank-workshop-claude-code.jpg"
|
||||
src={`${import.meta.env.BASE_URL}frank-workshop-claude-code.jpg`}
|
||||
alt="Frank Meeuwsen geeft een workshop over Claude Code"
|
||||
className="rounded-2xl shadow-lg w-full"
|
||||
style={{ filter: 'brightness(1.12) contrast(1.05) saturate(0.95)' }}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@
|
|||
* Pricing.jsx - "Investering" sectie
|
||||
*
|
||||
* Toont de prijs, inclusief lijst en urgency element.
|
||||
* Bevat primaire CTA button naar inschrijving.
|
||||
* Bevat primaire CTA button die naar Mollie betaalpagina linkt.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { PAYMENT_CONFIG } from '../config/payment';
|
||||
|
||||
function Pricing() {
|
||||
// Wat is inbegrepen
|
||||
const included = [
|
||||
|
|
@ -113,13 +116,13 @@ function Pricing() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
{/* CTA Button - naar inschrijfpagina */}
|
||||
<Link
|
||||
to={PAYMENT_CONFIG.SIGNUP_URL}
|
||||
className="btn-primary w-full text-center block"
|
||||
>
|
||||
Doe mee op 6 maart
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { PAYMENT_CONFIG } from '../config/payment';
|
||||
|
||||
function StickyBar() {
|
||||
// State om te bepalen of de bar zichtbaar moet zijn
|
||||
|
|
@ -63,12 +65,12 @@ function StickyBar() {
|
|||
<span className="font-display font-bold text-xl text-warm-900">
|
||||
€399 <span className="text-sm font-normal text-warm-500">excl. BTW</span>
|
||||
</span>
|
||||
<a
|
||||
href="#inschrijven"
|
||||
<Link
|
||||
to={PAYMENT_CONFIG.SIGNUP_URL}
|
||||
className="px-6 py-2 bg-coral-500 text-white font-semibold rounded-lg shadow-sm hover:bg-coral-600 transition-colors"
|
||||
>
|
||||
Inschrijven
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -89,12 +91,12 @@ function StickyBar() {
|
|||
</div>
|
||||
|
||||
{/* Right: CTA */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
<Link
|
||||
to={PAYMENT_CONFIG.SIGNUP_URL}
|
||||
className="flex-shrink-0 px-6 py-3 bg-coral-500 text-white font-semibold rounded-lg shadow-sm hover:bg-coral-600 transition-colors"
|
||||
>
|
||||
Inschrijven
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
11
src/config/payment.js
Normal file
11
src/config/payment.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* payment.js - Betaalflow configuratie
|
||||
*
|
||||
* CTA-knoppen linken naar de inschrijfpagina met embedded Tally formulier.
|
||||
* Na het formulier redirect Tally naar de Mollie betaalpagina.
|
||||
* Test/live Mollie link wordt ingesteld in Tally's redirect URL.
|
||||
*/
|
||||
|
||||
export const PAYMENT_CONFIG = {
|
||||
SIGNUP_URL: '/inschrijven',
|
||||
};
|
||||
|
|
@ -5,14 +5,18 @@ import './index.css'
|
|||
import App from './App.jsx'
|
||||
import Privacy from './pages/Privacy.jsx'
|
||||
import Terms from './pages/Terms.jsx'
|
||||
import ThankYou from './pages/ThankYou.jsx'
|
||||
import Signup from './pages/Signup.jsx'
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<BrowserRouter basename={import.meta.env.BASE_URL}>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/privacy" element={<Privacy />} />
|
||||
<Route path="/voorwaarden" element={<Terms />} />
|
||||
<Route path="/inschrijven" element={<Signup />} />
|
||||
<Route path="/bedankt" element={<ThankYou />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
|
|
|
|||
90
src/pages/Signup.jsx
Normal file
90
src/pages/Signup.jsx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* Signup.jsx - Inschrijfpagina met embedded Tally formulier
|
||||
*
|
||||
* Bezoekers komen hier via de CTA-knoppen op de sales page.
|
||||
* Na het invullen van het formulier redirect Tally naar de Mollie betaalpagina.
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Signup() {
|
||||
// Laad het Tally embed script zodra de pagina mount
|
||||
useEffect(() => {
|
||||
const scriptUrl = 'https://tally.so/widgets/embed.js';
|
||||
|
||||
// Check of het script al geladen is
|
||||
if (typeof window.Tally !== 'undefined') {
|
||||
window.Tally.loadEmbeds();
|
||||
return;
|
||||
}
|
||||
|
||||
// Script nog niet geladen? Voeg het toe
|
||||
if (!document.querySelector(`script[src="${scriptUrl}"]`)) {
|
||||
const script = document.createElement('script');
|
||||
script.src = scriptUrl;
|
||||
script.onload = () => {
|
||||
if (typeof window.Tally !== 'undefined') {
|
||||
window.Tally.loadEmbeds();
|
||||
}
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-warm-50">
|
||||
{/* Header */}
|
||||
<header className="bg-white border-b border-warm-200 py-6">
|
||||
<div className="container-page">
|
||||
<Link
|
||||
to="/"
|
||||
className="text-coral-500 hover:text-coral-600 transition-colors inline-flex items-center gap-2"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Terug naar workshop
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Content */}
|
||||
<main className="container-page py-12">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<h1 className="heading-hero mb-4 text-center">Inschrijven</h1>
|
||||
<p className="text-center text-warm-600 mb-10">
|
||||
Vul je gegevens in en je wordt doorgestuurd naar de betaalpagina.
|
||||
</p>
|
||||
|
||||
{/* Embedded Tally formulier */}
|
||||
<div className="card">
|
||||
<iframe
|
||||
data-tally-src="https://tally.so/embed/0Q6v8A?alignLeft=1&hideTitle=1&transparentBackground=1&dynamicHeight=1"
|
||||
loading="lazy"
|
||||
width="100%"
|
||||
height="300"
|
||||
frameBorder="0"
|
||||
title="Inschrijving Claude Code Workshop"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Workshop samenvatting */}
|
||||
<div className="mt-8 text-center text-sm text-warm-500 space-y-1">
|
||||
<p>Claude Code Workshop | Vrijdag 6 maart 2026 | 9:00 - 14:00 | Utrecht</p>
|
||||
<p>EUR 399 excl. BTW (EUR 482,79 incl. BTW)</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-warm-900 text-warm-400 py-6">
|
||||
<div className="container-page text-center text-sm">
|
||||
© {new Date().getFullYear()} Frank Meeuwsen. Alle rechten voorbehouden.
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Signup;
|
||||
108
src/pages/ThankYou.jsx
Normal file
108
src/pages/ThankYou.jsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* ThankYou.jsx - Bedankt-pagina na succesvolle betaling
|
||||
*
|
||||
* Bezoekers komen hier terecht na betaling via Mollie.
|
||||
* Toont bevestiging, workshop details en vervolgstappen.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function ThankYou() {
|
||||
return (
|
||||
<div className="min-h-screen bg-warm-50">
|
||||
{/* Header */}
|
||||
<header className="bg-white border-b border-warm-200 py-6">
|
||||
<div className="container-page">
|
||||
<Link
|
||||
to="/"
|
||||
className="text-coral-500 hover:text-coral-600 transition-colors inline-flex items-center gap-2"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Terug naar homepage
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Content */}
|
||||
<main className="container-page py-12">
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
{/* Checkmark icoon */}
|
||||
<div className="mx-auto w-20 h-20 bg-teal-100 rounded-full flex items-center justify-center mb-8">
|
||||
<svg className="w-10 h-10 text-teal-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1 className="heading-hero mb-4">Je bent erbij!</h1>
|
||||
<p className="text-xl text-warm-600 mb-10">
|
||||
Je inschrijving voor de Claude Code Workshop is bevestigd.
|
||||
</p>
|
||||
|
||||
{/* Workshop details */}
|
||||
<div className="card text-left mb-10">
|
||||
<h2 className="heading-3 mb-4">Workshop details</h2>
|
||||
<div className="space-y-3 text-warm-600">
|
||||
<div className="flex gap-3">
|
||||
<svg className="w-5 h-5 text-coral-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span>Vrijdag 6 maart 2026</span>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<svg className="w-5 h-5 text-coral-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>9:00 - 14:00 uur</span>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<svg className="w-5 h-5 text-coral-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
<span>Utrecht</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Vervolgstappen */}
|
||||
<div className="card text-left mb-10">
|
||||
<h2 className="heading-3 mb-4">Wat gebeurt er nu?</h2>
|
||||
<ol className="space-y-4 text-warm-600">
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-7 h-7 bg-coral-100 text-coral-600 rounded-full flex items-center justify-center font-semibold text-sm">1</span>
|
||||
<span>Je ontvangt een bevestigingsmail met je factuur.</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-7 h-7 bg-coral-100 text-coral-600 rounded-full flex items-center justify-center font-semibold text-sm">2</span>
|
||||
<span>Een week voor de workshop ontvang je een mail met praktische informatie en voorbereidingsinstructies.</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-7 h-7 bg-coral-100 text-coral-600 rounded-full flex items-center justify-center font-semibold text-sm">3</span>
|
||||
<span>Op 6 maart neem je je laptop mee en gaan we aan de slag!</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Contact */}
|
||||
<p className="text-warm-500">
|
||||
Vragen? Mail naar{' '}
|
||||
<a href="mailto:frank@frankmeeuwsen.com" className="text-coral-500 hover:text-coral-600">
|
||||
frank@frankmeeuwsen.com
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-warm-900 text-warm-400 py-6">
|
||||
<div className="container-page text-center text-sm">
|
||||
© {new Date().getFullYear()} Frank Meeuwsen. Alle rechten voorbehouden.
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ThankYou;
|
||||
|
|
@ -2,6 +2,8 @@ import { defineConfig } from 'vite'
|
|||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
// base path alleen voor production build, lokaal blijft het op /
|
||||
export default defineConfig(({ command }) => ({
|
||||
plugins: [react()],
|
||||
})
|
||||
base: command === 'build' ? '/workshopclaudecode/' : '/',
|
||||
}))
|
||||
|
|
|
|||
Loading…
Reference in a new issue