feat: initiële setup Claude Code Workshop sales page
- Hero met twee-kolommen layout en afbeelding placeholder - Workshop details prominent met datum, tijd, locatie - React Router met Privacy en Voorwaarden pagina's - Alle secties: PainPoints, Benefits, Program, ForWho, Trainer, Pricing, FAQ, Testimonials - Footer met contact en juridische links - Tailwind CSS styling met custom warm/coral/teal kleuren Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
06ecb5157c
33 changed files with 6153 additions and 0 deletions
3
.dashboard.yml
Normal file
3
.dashboard.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
port: 5173
|
||||
start_command: npm run dev
|
||||
description: Claude Code Workshop Sales Page
|
||||
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Session tracking
|
||||
.session-start
|
||||
35
LOGBOEK.md
Normal file
35
LOGBOEK.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Project Logboek - Claude Code Workshop Sales Page
|
||||
|
||||
## 2025-01-29 - Sessie 1: Initiële setup en content aanpassingen (~25m)
|
||||
|
||||
### Wat is gebouwd
|
||||
- Hero sectie uitgebreid met twee-kolommen layout (tekst links, afbeelding placeholder rechts)
|
||||
- Workshop details (datum, tijd, locatie) prominent gemaakt met grote iconen en labels
|
||||
- Testimonials sectie verplaatst naar boven "Wat je meeneemt naar huis"
|
||||
- React Router toegevoegd voor pagina navigatie
|
||||
- Privacy pagina aangemaakt (/privacy) met standaard tekst
|
||||
- Algemene Voorwaarden pagina aangemaakt (/voorwaarden) met standaard tekst
|
||||
- Footer bijgewerkt met werkende links naar juridische pagina's
|
||||
|
||||
### Content aanpassingen
|
||||
- Lunch tekst: "Wonders of Work heeft een heerlijke lunch voor ons klaarstaan..."
|
||||
- Kleuren omgewisseld: "Wat je nodig hebt" = groen (teal), "Wat je niet nodig hebt" = rood (coral)
|
||||
- Social links toegevoegd: LinkedIn (linkedin.com/in/frankmeeuwsen), Website (frankmeeuwsen.com)
|
||||
- Prijs: €449 excl. BTW (was incl. BTW)
|
||||
- Verwijderd uit inbegrepen: werkboek en community access
|
||||
- "Vol is vol" tekst verwijderd
|
||||
- FAQ "geld terug" vraag verwijderd
|
||||
- Footer: "Claude Code Hands-on Sessie" + email contact + LinkedIn
|
||||
- Contact: alleen email (frank@frankmeeuwsen.com) en LinkedIn, geen telefoon
|
||||
|
||||
### Technische beslissingen
|
||||
- React Router DOM toegevoegd voor multi-page support
|
||||
- Aparte pages folder aangemaakt voor Privacy en Terms componenten
|
||||
- Link componenten gebruikt voor interne navigatie (SEO-vriendelijk)
|
||||
|
||||
### Volgende sessie
|
||||
- [ ] Echte afbeelding toevoegen in Hero placeholder
|
||||
- [ ] Bio tekst invullen in Trainer sectie
|
||||
- [ ] Privacy en Voorwaarden teksten finaliseren
|
||||
- [ ] Testimonials content toevoegen (echte quotes)
|
||||
- [ ] Inschrijfformulier/betaallink toevoegen
|
||||
16
README.md
Normal file
16
README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# React + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## React Compiler
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
BIN
content/claudecodeworkshop.jpg
Normal file
BIN
content/claudecodeworkshop.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
251
content/workshop-sales-page.md
Normal file
251
content/workshop-sales-page.md
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
# Claude Code Workshop - Sales Page Content
|
||||
|
||||
## 1. Hero Section
|
||||
|
||||
### Headline
|
||||
**Van "dit moet ik uitzoeken" naar "dit werkt gewoon"**
|
||||
|
||||
### Subheadline
|
||||
In 1 ochtend van nieuwsgierig naar praktisch aan de slag met Claude Code. Je gaat naar huis met je eigen werkende project.
|
||||
|
||||
### Intro
|
||||
Je hebt van Claude Code gehoord. Misschien zelfs al even mee gespeeld. Maar ergens tussen de installatie en dat eerste echte resultaat ben je blijven hangen. Herkenbaar? In deze hands-on workshop doorbreek je die drempel. Samen met maximaal 6 andere ondernemers ga je van nul naar een werkend project dat je direct kunt gebruiken in je business.
|
||||
|
||||
### CTA
|
||||
**Schrijf je in - nog [X] plaatsen**
|
||||
|
||||
---
|
||||
|
||||
## 2. Pain Points ("Herkenbaar?")
|
||||
|
||||
### Section Title
|
||||
**Herkenbaar?**
|
||||
|
||||
### Pain Points
|
||||
|
||||
- Je hebt YouTube tutorials gekeken, maar zodra je zelf begint loopt het anders dan in de video?
|
||||
|
||||
- Je weet dat AI tools je kunnen helpen, maar je hebt geen idee waar je moet beginnen met Claude Code?
|
||||
|
||||
- Je collega's of concurrenten werken al met AI, en jij bent nog aan het uitzoeken hoe het werkt?
|
||||
|
||||
- Je hebt weinig tijd om te experimenteren, en trial-and-error voelt als verspilling van kostbare uren?
|
||||
|
||||
Da's frustrerend. Want je weet dat je sneller zou kunnen werken, betere output zou kunnen leveren. Maar die drempel... die blijft maar in de weg zitten.
|
||||
|
||||
---
|
||||
|
||||
## 3. Benefits / Solution
|
||||
|
||||
### Section Title
|
||||
**Wat je meeneemt naar huis**
|
||||
|
||||
### Benefits
|
||||
|
||||
- **Een werkend project** - Geen theorie, maar iets dat je maandag direct kunt gebruiken in je business.
|
||||
|
||||
- **Zelfvertrouwen met Claude Code** - Je snapt hoe het werkt, waarom het werkt, en wat je ermee kunt.
|
||||
|
||||
- **Je eigen setup die klopt** - Goed geconfigureerd, afgestemd op jouw manier van werken.
|
||||
|
||||
- **Praktische workflows** - Hoe je Claude Code inzet voor taken die jij dagelijks doet.
|
||||
|
||||
- **Kennis van agents en skills** - De krachtigere features waar de meeste mensen nooit aan toekomen.
|
||||
|
||||
- **Een netwerk van mede-ondernemers** - Zeven mensen die dezelfde reis maken. Handig voor vragen achteraf.
|
||||
|
||||
- **Vervolgstappen die bij jou passen** - Geen generiek advies, maar concrete volgende stappen voor jouw situatie.
|
||||
|
||||
---
|
||||
|
||||
## 4. Workshop Programma
|
||||
|
||||
### Section Title
|
||||
**Zo ziet je dag eruit**
|
||||
|
||||
### Programma
|
||||
|
||||
**09:00 - Welkom en setup**
|
||||
We zorgen dat iedereen een werkende Claude Code installatie heeft. Vastlopers lossen we direct samen op.
|
||||
|
||||
**09:30 - De basis begrijpen**
|
||||
Je leert de interface, de belangrijkste commando's, en hoe Claude Code denkt. Geen droge theorie, maar direct toepassen.
|
||||
|
||||
**10:30 - Eerste hands-on oefening**
|
||||
Je eerste echte project. Klein, overzichtelijk, en direct resultaat. Hier voel je hoe het werkt.
|
||||
|
||||
**11:30 - Lunch**
|
||||
Tijd om bij te praten met je mede-deelnemers. Netwerkmoment met broodjes en koffie.
|
||||
|
||||
**12:15 - Je eigen project starten**
|
||||
Nu wordt het persoonlijk. Je werkt aan iets voor jouw business. Ik loop rond, help waar nodig, en zorg dat je niet vastloopt.
|
||||
|
||||
**13:15 - Agents en skills**
|
||||
De krachtigere features. Hoe je Claude Code laat samenwerken met andere tools en hoe je complexere taken automatiseert.
|
||||
|
||||
**13:45 - Afronden en vervolgstappen**
|
||||
We kijken naar wat je hebt gebouwd. Je krijgt concrete vervolgstappen die passen bij waar jij nu staat.
|
||||
|
||||
**14:00 - Einde**
|
||||
|
||||
---
|
||||
|
||||
## 5. Voor Wie
|
||||
|
||||
### Section Title
|
||||
**Is deze workshop iets voor jou?**
|
||||
|
||||
### Ideale Deelnemer
|
||||
|
||||
Deze workshop is voor jou als:
|
||||
|
||||
- Je bent ZZP'er of ondernemer in het MKB
|
||||
- Je wilt AI praktisch inzetten, niet alleen erover lezen
|
||||
- Je hebt geen of weinig ervaring met Claude Code (maar wel nieuwsgierigheid)
|
||||
- Je bent bereid een ochtend te investeren om echt te leren
|
||||
- Je wilt werken aan je eigen project, niet aan een standaard oefening
|
||||
|
||||
### Vereisten
|
||||
|
||||
**Wat je nodig hebt:**
|
||||
- Een laptop die je meeneemt
|
||||
- Een betaald Claude account (Pro of Max) - dit heb je vooraf geregeld
|
||||
- Basiskennis van je computer (bestanden openen, software installeren)
|
||||
|
||||
**Wat je niet nodig hebt:**
|
||||
- Programmeerervaring
|
||||
- Eerdere AI kennis
|
||||
- Technische achtergrond
|
||||
|
||||
---
|
||||
|
||||
## 6. Over de Trainer
|
||||
|
||||
### Section Title
|
||||
**Je trainer**
|
||||
|
||||
### Bio Placeholder
|
||||
|
||||
[FOTO FRANK]
|
||||
|
||||
**Frank Meeuwsen**
|
||||
|
||||
[Korte bio - 2-3 zinnen over Frank's achtergrond met AI en Claude Code]
|
||||
|
||||
[Relevante ervaring/credentials]
|
||||
|
||||
[Persoonlijke noot over waarom hij deze workshop geeft]
|
||||
|
||||
---
|
||||
|
||||
## 7. Pricing Section
|
||||
|
||||
### Section Title
|
||||
**Investering**
|
||||
|
||||
### Pricing Block
|
||||
|
||||
**EUR 449** per persoon (inclusief BTW)
|
||||
|
||||
**Inbegrepen:**
|
||||
- Volledige workshop (9:00 - 14:00)
|
||||
- Lunch en onbeperkt koffie/thee
|
||||
- Werkboek met alle commando's en tips
|
||||
- Toegang tot de besloten community voor vragen achteraf
|
||||
- Persoonlijke begeleiding bij je project
|
||||
|
||||
### Urgency Element
|
||||
|
||||
**Let op:** Maximaal 7 deelnemers per workshop. Dit is bewust klein gehouden zodat iedereen persoonlijke aandacht krijgt. Vol is vol.
|
||||
|
||||
### CTA
|
||||
**Reserveer je plek**
|
||||
|
||||
---
|
||||
|
||||
## 8. FAQ
|
||||
|
||||
### Section Title
|
||||
**Veelgestelde vragen**
|
||||
|
||||
### FAQ Items
|
||||
|
||||
**Ik heb nog nooit geprogrammeerd. Kan ik meedoen?**
|
||||
Ja. Claude Code is juist gemaakt voor mensen zonder technische achtergrond. Je typt wat je wilt, Claude Code doet het zware werk. De workshop is specifiek ontworpen voor niet-programmeurs.
|
||||
|
||||
**Wat is een Claude Pro of Max account en waarom heb ik dat nodig?**
|
||||
Dit is een betaald abonnement bij Anthropic (het bedrijf achter Claude). Pro kost ongeveer 20 euro per maand, Max ongeveer 100 euro. Je hebt dit nodig om Claude Code te kunnen gebruiken. Aanmelden kan via claude.ai.
|
||||
|
||||
**Moet ik iets voorbereiden?**
|
||||
Je ontvangt vooraf een korte handleiding om Claude Code te installeren. Lukt dat niet? Geen probleem, we helpen je aan het begin van de workshop.
|
||||
|
||||
**Wat voor project ga ik bouwen?**
|
||||
Dat bepaal je zelf. Vooraf bespreken we kort wat voor jou relevant is. Denk aan: een simpele website, een automatisering, een tool die je dagelijks werk makkelijker maakt. We zorgen dat het haalbaar is binnen de tijd.
|
||||
|
||||
**Kan ik mijn geld terugkrijgen als ik niet kan komen?**
|
||||
Tot 7 dagen voor de workshop krijg je het volledige bedrag terug. Daarna kun je iemand anders in je plaats sturen.
|
||||
|
||||
**Ik heb al wat ervaring met Claude. Is dit dan niet te basic?**
|
||||
De workshop begint bij de basis, maar gaat vrij snel naar de interessantere features zoals agents en skills. Je werkt aan je eigen tempo en project, dus ook met voorkennis haal je er genoeg uit.
|
||||
|
||||
---
|
||||
|
||||
## 9. Testimonials Section
|
||||
|
||||
### Section Title
|
||||
**Wat deelnemers zeggen**
|
||||
|
||||
### Testimonial Template
|
||||
|
||||
[Testimonials worden toegevoegd na de eerste workshops]
|
||||
|
||||
**Voorbeeld structuur:**
|
||||
|
||||
> "[Quote over specifieke ervaring of resultaat]"
|
||||
>
|
||||
> **[Naam]** - [Functie/Bedrijf]
|
||||
|
||||
### Placeholder voor 3-5 testimonials
|
||||
|
||||
```
|
||||
Testimonial 1: Focus op "aha-moment" of doorbraak
|
||||
Testimonial 2: Focus op praktische toepassing na de workshop
|
||||
Testimonial 3: Focus op de begeleiding/sfeer
|
||||
Testimonial 4: Focus op specifiek resultaat/project
|
||||
Testimonial 5: Focus op ROI of tijdsbesparing
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Final CTA
|
||||
|
||||
### Section Title
|
||||
**Klaar om te beginnen?**
|
||||
|
||||
### Closing Text
|
||||
|
||||
De volgende workshop is op **vrijdag 6 maart 2026** in Utrecht. We starten om 9:00, rond 14:00 ga je naar huis met je eigen werkende project.
|
||||
|
||||
Zeven plaatsen. Persoonlijke begeleiding. Geen PowerPoint-presentaties, maar handen uit de mouwen.
|
||||
|
||||
### CTA
|
||||
**Schrijf je in voor 6 maart**
|
||||
|
||||
### Laatste noot
|
||||
Vragen? Mail naar [email] of bel [nummer]. Ik help je graag.
|
||||
|
||||
---
|
||||
|
||||
## Aanvullende Elementen
|
||||
|
||||
### Trust Indicators (voor header/footer)
|
||||
- Locatie: Wonders of Work, Utrecht
|
||||
- Datum: Vrijdag 6 maart 2026
|
||||
- Tijd: 9:00 - 14:00
|
||||
- Max 7 deelnemers
|
||||
|
||||
### Meta Description (SEO)
|
||||
Claude Code Workshop voor ZZP'ers en MKB ondernemers. Van nieuwsgierig naar praktisch aan de slag in 1 ochtend. Max 7 deelnemers, persoonlijke begeleiding. 6 maart 2026, Utrecht.
|
||||
|
||||
### Page Title (SEO)
|
||||
Claude Code Workshop | Van 0 naar werkend project in 1 ochtend | 6 maart 2026
|
||||
29
eslint.config.js
Normal file
29
eslint.config.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
reactHooks.configs.flat.recommended,
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
},
|
||||
},
|
||||
])
|
||||
19
index.html
Normal file
19
index.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!doctype html>
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.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." />
|
||||
|
||||
<!-- Google Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@600;700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
3854
package-lock.json
generated
Normal file
3854
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
31
package.json
Normal file
31
package.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "cc-course",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-router-dom": "^7.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@types/react": "^19.2.5",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.5.0",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"vite": "^7.2.4"
|
||||
}
|
||||
}
|
||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
67
src/App.jsx
Normal file
67
src/App.jsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* App.jsx - Hoofdcomponent voor de Claude Code Workshop sales page
|
||||
*
|
||||
* Importeert en rendert alle secties in de juiste volgorde.
|
||||
* De StickyBar wordt als laatste gerenderd zodat deze boven alles staat.
|
||||
*/
|
||||
|
||||
// Component imports
|
||||
import Hero from './components/Hero';
|
||||
import PainPoints from './components/PainPoints';
|
||||
import Benefits from './components/Benefits';
|
||||
import Program from './components/Program';
|
||||
import ForWho from './components/ForWho';
|
||||
import Trainer from './components/Trainer';
|
||||
import Pricing from './components/Pricing';
|
||||
import Testimonials from './components/Testimonials';
|
||||
import FAQ from './components/FAQ';
|
||||
import FinalCTA from './components/FinalCTA';
|
||||
import Footer from './components/Footer';
|
||||
import StickyBar from './components/StickyBar';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
{/* Main content */}
|
||||
<main>
|
||||
{/* 1. Hero - eerste indruk met headline en CTA */}
|
||||
<Hero />
|
||||
|
||||
{/* 2. Pain Points - herkenbare frustraties */}
|
||||
<PainPoints />
|
||||
|
||||
{/* 3. Testimonials - wat deelnemers zeggen (nu boven Benefits) */}
|
||||
<Testimonials />
|
||||
|
||||
{/* 4. Benefits - wat je meeneemt naar huis */}
|
||||
<Benefits />
|
||||
|
||||
{/* 5. Program - dagindeling */}
|
||||
<Program />
|
||||
|
||||
{/* 6. For Who - doelgroep en vereisten */}
|
||||
<ForWho />
|
||||
|
||||
{/* 7. Trainer - over Frank */}
|
||||
<Trainer />
|
||||
|
||||
{/* 8. Pricing - investering en CTA */}
|
||||
<Pricing />
|
||||
|
||||
{/* 9. FAQ - veelgestelde vragen */}
|
||||
<FAQ />
|
||||
|
||||
{/* 10. Final CTA - afsluitende call-to-action */}
|
||||
<FinalCTA />
|
||||
</main>
|
||||
|
||||
{/* 11. Footer */}
|
||||
<Footer />
|
||||
|
||||
{/* 12. Sticky Bar - verschijnt na scroll */}
|
||||
<StickyBar />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
0
src/components/.gitkeep
Normal file
0
src/components/.gitkeep
Normal file
117
src/components/Benefits.jsx
Normal file
117
src/components/Benefits.jsx
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* Benefits.jsx - "Wat je meeneemt naar huis" sectie
|
||||
*
|
||||
* Toont de 7 benefits van de workshop met icons.
|
||||
* Gebruikt card-feature styling voor een premium look.
|
||||
*/
|
||||
|
||||
function Benefits() {
|
||||
// De 7 benefits met passende icons (inline SVG)
|
||||
const benefits = [
|
||||
{
|
||||
title: "Een werkend project",
|
||||
description: "Geen theorie, maar iets dat je maandag direct kunt gebruiken in je business.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Zelfvertrouwen met Claude Code",
|
||||
description: "Je snapt hoe het werkt, waarom het werkt, en wat je ermee kunt.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Je eigen setup die klopt",
|
||||
description: "Goed geconfigureerd, afgestemd op jouw manier van werken.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Praktische workflows",
|
||||
description: "Hoe je Claude Code inzet voor taken die jij dagelijks doet.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Kennis van agents en skills",
|
||||
description: "De krachtigere features waar de meeste mensen nooit aan toekomen.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Een netwerk van mede-ondernemers",
|
||||
description: "Zeven mensen die dezelfde reis maken. Handig voor vragen achteraf.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Vervolgstappen die bij jou passen",
|
||||
description: "Geen generiek advies, maar concrete volgende stappen voor jouw situatie.",
|
||||
icon: (
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-4">
|
||||
Wat je meeneemt naar huis
|
||||
</h2>
|
||||
<p className="text-warm-600 text-center mb-12 max-w-2xl mx-auto">
|
||||
Na deze workshop heb je niet alleen kennis, maar ook resultaat.
|
||||
</p>
|
||||
|
||||
{/* Benefits grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto">
|
||||
{benefits.map((benefit, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="card-feature group"
|
||||
>
|
||||
{/* Icon */}
|
||||
<div className="w-12 h-12 rounded-xl bg-coral-100 text-coral-600 flex items-center justify-center mb-4 group-hover:bg-coral-500 group-hover:text-white transition-colors duration-200">
|
||||
{benefit.icon}
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h3 className="font-display font-semibold text-lg text-warm-900 mb-2">
|
||||
{benefit.title}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-warm-600 leading-relaxed">
|
||||
{benefit.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Benefits;
|
||||
113
src/components/FAQ.jsx
Normal file
113
src/components/FAQ.jsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* FAQ.jsx - "Veelgestelde vragen" sectie
|
||||
*
|
||||
* Accordion component met 6 FAQ items.
|
||||
* Klikbaar om te openen/sluiten met chevron icon animatie.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
function FAQ() {
|
||||
// State om bij te houden welke items open zijn
|
||||
// We gebruiken een array zodat meerdere items tegelijk open kunnen
|
||||
const [openItems, setOpenItems] = useState([]);
|
||||
|
||||
// Toggle functie voor een item
|
||||
const toggleItem = (index) => {
|
||||
if (openItems.includes(index)) {
|
||||
// Item is al open, sluit het
|
||||
setOpenItems(openItems.filter(i => i !== index));
|
||||
} else {
|
||||
// Item is dicht, open het
|
||||
setOpenItems([...openItems, index]);
|
||||
}
|
||||
};
|
||||
|
||||
// FAQ items uit de content
|
||||
const faqItems = [
|
||||
{
|
||||
question: "Ik heb nog nooit geprogrammeerd. Kan ik meedoen?",
|
||||
answer: "Ja. Claude Code is juist gemaakt voor mensen zonder technische achtergrond. Je typt wat je wilt, Claude Code doet het zware werk. De workshop is specifiek ontworpen voor niet-programmeurs."
|
||||
},
|
||||
{
|
||||
question: "Wat is een Claude Pro of Max account en waarom heb ik dat nodig?",
|
||||
answer: "Dit is een betaald abonnement bij Anthropic (het bedrijf achter Claude). Pro kost ongeveer 20 euro per maand, Max ongeveer 100 euro. Je hebt dit nodig om Claude Code te kunnen gebruiken. Aanmelden kan via claude.ai."
|
||||
},
|
||||
{
|
||||
question: "Moet ik iets voorbereiden?",
|
||||
answer: "Je ontvangt vooraf een korte handleiding om Claude Code te installeren. Lukt dat niet? Geen probleem, we helpen je aan het begin van de workshop."
|
||||
},
|
||||
{
|
||||
question: "Wat voor project ga ik bouwen?",
|
||||
answer: "Dat bepaal je zelf. Vooraf bespreken we kort wat voor jou relevant is. Denk aan: een simpele website, een automatisering, een tool die je dagelijks werk makkelijker maakt. We zorgen dat het haalbaar is binnen de tijd."
|
||||
},
|
||||
{
|
||||
question: "Ik heb al wat ervaring met Claude. Is dit dan niet te basic?",
|
||||
answer: "De workshop begint bij de basis, maar gaat vrij snel naar de interessantere features zoals agents en skills. Je werkt aan je eigen tempo en project, dus ook met voorkennis haal je er genoeg uit."
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section-alt">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-12">
|
||||
Veelgestelde vragen
|
||||
</h2>
|
||||
|
||||
{/* FAQ accordion */}
|
||||
<div className="max-w-3xl mx-auto space-y-4">
|
||||
{faqItems.map((item, index) => {
|
||||
const isOpen = openItems.includes(index);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white rounded-xl border border-warm-200 overflow-hidden"
|
||||
>
|
||||
{/* Question button */}
|
||||
<button
|
||||
onClick={() => toggleItem(index)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between text-left hover:bg-warm-50 transition-colors"
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
<span className="font-semibold text-warm-900 pr-4">
|
||||
{item.question}
|
||||
</span>
|
||||
|
||||
{/* Chevron icon - roteert bij open */}
|
||||
<svg
|
||||
className={`w-5 h-5 text-coral-500 flex-shrink-0 transition-transform duration-200 ${
|
||||
isOpen ? 'rotate-180' : ''
|
||||
}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Answer - conditionally rendered */}
|
||||
{isOpen && (
|
||||
<div className="px-6 pb-4">
|
||||
<p className="text-warm-600 leading-relaxed">
|
||||
{item.answer}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default FAQ;
|
||||
87
src/components/FinalCTA.jsx
Normal file
87
src/components/FinalCTA.jsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* FinalCTA.jsx - Afsluitende call-to-action sectie
|
||||
*
|
||||
* Coral-500 achtergrond met witte tekst.
|
||||
* Bevat datum, locatie en primaire CTA button (wit met coral tekst).
|
||||
*/
|
||||
|
||||
function FinalCTA() {
|
||||
return (
|
||||
<section className="py-16 lg:py-24 bg-coral-500 relative overflow-hidden">
|
||||
{/* Decoratieve elementen */}
|
||||
<div
|
||||
className="absolute top-0 left-0 w-64 h-64 bg-coral-400 rounded-full blur-3xl opacity-50"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div
|
||||
className="absolute bottom-0 right-0 w-96 h-96 bg-coral-600 rounded-full blur-3xl opacity-30"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<div className="container-page relative">
|
||||
<div className="max-w-3xl mx-auto text-center">
|
||||
{/* Headline */}
|
||||
<h2 className="font-display text-3xl md:text-4xl font-bold text-white mb-6">
|
||||
Klaar om te beginnen?
|
||||
</h2>
|
||||
|
||||
{/* Closing text */}
|
||||
<p className="text-xl text-coral-100 mb-8 leading-relaxed">
|
||||
De volgende workshop is op{' '}
|
||||
<span className="text-white font-semibold">vrijdag 6 maart 2026</span>
|
||||
{' '}in Utrecht. We starten om 9:00, rond 14:00 ga je naar huis met
|
||||
je eigen werkende project.
|
||||
</p>
|
||||
|
||||
{/* Highlights */}
|
||||
<div className="flex flex-wrap justify-center gap-6 mb-10 text-coral-100">
|
||||
<div className="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="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
<span>7 plaatsen</span>
|
||||
</div>
|
||||
<div className="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="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
<span>Persoonlijke begeleiding</span>
|
||||
</div>
|
||||
<div className="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="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span>Hands-on, geen PowerPoints</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button - wit met coral tekst */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
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"
|
||||
>
|
||||
Schrijf je in voor 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>
|
||||
|
||||
{/* Contact info */}
|
||||
<p className="mt-8 text-coral-200">
|
||||
Vragen? Mail naar{' '}
|
||||
<a href="mailto:contact@example.com" className="text-white underline hover:no-underline">
|
||||
[email]
|
||||
</a>
|
||||
{' '}of bel{' '}
|
||||
<a href="tel:+31600000000" className="text-white underline hover:no-underline">
|
||||
[nummer]
|
||||
</a>
|
||||
. Ik help je graag.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default FinalCTA;
|
||||
122
src/components/Footer.jsx
Normal file
122
src/components/Footer.jsx
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Footer.jsx - Website footer
|
||||
*
|
||||
* Donkere achtergrond (warm-900) met workshop info,
|
||||
* contact placeholder en copyright.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Footer() {
|
||||
// Huidig jaar voor copyright
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="bg-warm-900 text-warm-300 py-12">
|
||||
<div className="container-page">
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
{/* Workshop info */}
|
||||
<div>
|
||||
<h3 className="font-display font-semibold text-white mb-4">
|
||||
Claude Code Hands-on Sessie
|
||||
</h3>
|
||||
<p className="text-sm leading-relaxed">
|
||||
Van nieuwsgierig naar praktisch aan de slag met Claude Code.
|
||||
Max 7 deelnemers, persoonlijke begeleiding.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Volgende workshop */}
|
||||
<div>
|
||||
<h3 className="font-display font-semibold text-white mb-4">
|
||||
Volgende workshop
|
||||
</h3>
|
||||
<ul className="space-y-2 text-sm">
|
||||
<li className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-coral-400" 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>
|
||||
Vrijdag 6 maart 2026
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-coral-400" 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>
|
||||
9:00 - 14:00
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<svg className="w-4 h-4 text-coral-400" 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>
|
||||
Wonders of Work, Utrecht
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Contact */}
|
||||
<div>
|
||||
<h3 className="font-display font-semibold text-white mb-4">
|
||||
Contact
|
||||
</h3>
|
||||
<p className="text-sm leading-relaxed mb-4">
|
||||
Vragen? Mail naar{' '}
|
||||
<a href="mailto:frank@frankmeeuwsen.com" className="text-coral-400 hover:text-coral-300 transition-colors">
|
||||
frank@frankmeeuwsen.com
|
||||
</a>
|
||||
{' '}en ik help je graag!
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm">
|
||||
<li>
|
||||
<a
|
||||
href="mailto:frank@frankmeeuwsen.com"
|
||||
className="hover:text-coral-400 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<svg className="w-4 h-4 text-coral-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
frank@frankmeeuwsen.com
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.linkedin.com/in/frankmeeuwsen"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-coral-400 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<svg className="w-4 h-4 text-coral-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
|
||||
</svg>
|
||||
LinkedIn profiel
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="border-t border-warm-800 mt-10 pt-6">
|
||||
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
{/* Copyright */}
|
||||
<p className="text-sm text-warm-500">
|
||||
© {currentYear} Frank Meeuwsen. Alle rechten voorbehouden.
|
||||
</p>
|
||||
|
||||
{/* Links */}
|
||||
<div className="flex gap-6 text-sm">
|
||||
<Link to="/privacy" className="hover:text-coral-400 transition-colors">
|
||||
Privacy
|
||||
</Link>
|
||||
<Link to="/voorwaarden" className="hover:text-coral-400 transition-colors">
|
||||
Algemene voorwaarden
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
142
src/components/ForWho.jsx
Normal file
142
src/components/ForWho.jsx
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* ForWho.jsx - "Is deze workshop iets voor jou?" sectie
|
||||
*
|
||||
* Bevat drie delen:
|
||||
* 1. "Deze workshop is voor jou als:" lijst
|
||||
* 2. "Wat je nodig hebt" kolom
|
||||
* 3. "Wat je niet nodig hebt" kolom
|
||||
*/
|
||||
|
||||
function ForWho() {
|
||||
// Ideale deelnemer kenmerken
|
||||
const idealFor = [
|
||||
"Je bent ZZP'er of ondernemer in het MKB",
|
||||
"Je wilt AI praktisch inzetten, niet alleen erover lezen",
|
||||
"Je hebt geen of weinig ervaring met Claude Code (maar wel nieuwsgierigheid)",
|
||||
"Je bent bereid een ochtend te investeren om echt te leren",
|
||||
"Je wilt werken aan je eigen project, niet aan een standaard oefening"
|
||||
];
|
||||
|
||||
// Wat je nodig hebt
|
||||
const requirements = [
|
||||
"Een laptop die je meeneemt",
|
||||
"Een betaald Claude account (Pro of Max) - dit heb je vooraf geregeld",
|
||||
"Basiskennis van je computer (bestanden openen, software installeren)"
|
||||
];
|
||||
|
||||
// Wat je niet nodig hebt
|
||||
const notRequired = [
|
||||
"Programmeerervaring",
|
||||
"Eerdere AI kennis",
|
||||
"Technische achtergrond"
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-12">
|
||||
Is deze workshop iets voor jou?
|
||||
</h2>
|
||||
|
||||
{/* Ideal deelnemer */}
|
||||
<div className="max-w-3xl mx-auto mb-12">
|
||||
<h3 className="heading-3 mb-6">
|
||||
Deze workshop is voor jou als:
|
||||
</h3>
|
||||
|
||||
<ul className="space-y-4">
|
||||
{idealFor.map((item, index) => (
|
||||
<li key={index} className="flex gap-3">
|
||||
{/* Check icon */}
|
||||
<svg
|
||||
className="w-6 h-6 text-teal-500 flex-shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-warm-700 text-lg">{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Requirements grid */}
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
|
||||
{/* Wat je nodig hebt - GROEN */}
|
||||
<div className="card border-l-4 border-l-teal-500">
|
||||
<h3 className="font-display font-semibold text-lg text-warm-900 mb-4 flex items-center gap-2">
|
||||
{/* Check icon */}
|
||||
<svg className="w-5 h-5 text-teal-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Wat je nodig hebt
|
||||
</h3>
|
||||
|
||||
<ul className="space-y-3">
|
||||
{requirements.map((item, index) => (
|
||||
<li key={index} className="flex gap-3 text-warm-600">
|
||||
<svg
|
||||
className="w-5 h-5 text-teal-500 flex-shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Wat je niet nodig hebt - ROOD */}
|
||||
<div className="card bg-warm-50 border-l-4 border-l-coral-500">
|
||||
<h3 className="font-display font-semibold text-lg text-warm-900 mb-4 flex items-center gap-2">
|
||||
{/* X icon */}
|
||||
<svg className="w-5 h-5 text-coral-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
||||
</svg>
|
||||
Wat je niet nodig hebt
|
||||
</h3>
|
||||
|
||||
<ul className="space-y-3">
|
||||
{notRequired.map((item, index) => (
|
||||
<li key={index} className="flex gap-3 text-warm-600">
|
||||
<svg
|
||||
className="w-5 h-5 text-coral-400 flex-shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForWho;
|
||||
138
src/components/Hero.jsx
Normal file
138
src/components/Hero.jsx
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Hero.jsx - De eerste sectie die bezoekers zien
|
||||
*
|
||||
* Bevat de hoofdboodschap, subheadline, intro tekst en primaire CTA.
|
||||
* Gebruikt coral accent kleuren en een decoratieve blob op de achtergrond.
|
||||
*/
|
||||
|
||||
function Hero() {
|
||||
// Aantal beschikbare plaatsen - later dynamisch te maken
|
||||
const availableSpots = 7;
|
||||
|
||||
return (
|
||||
<section className="section relative overflow-hidden">
|
||||
{/* Decoratieve blob op achtergrond */}
|
||||
<div
|
||||
className="absolute -top-40 -right-40 w-96 h-96 bg-coral-100 rounded-full blur-3xl opacity-60"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div
|
||||
className="absolute -bottom-20 -left-20 w-64 h-64 bg-teal-100 rounded-full blur-3xl opacity-40"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<div className="container-page relative">
|
||||
{/* Twee-kolommen layout: tekst links, afbeelding rechts */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Linker kolom: tekst content */}
|
||||
<div>
|
||||
{/* Urgency badge */}
|
||||
<div className="mb-6">
|
||||
<span className="inline-flex items-center gap-2 px-4 py-2 bg-coral-100 text-coral-700 rounded-full text-sm font-medium">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-coral-500 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-coral-500"></span>
|
||||
</span>
|
||||
Maximaal {availableSpots} plaatsen
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Headline */}
|
||||
<h1 className="heading-hero mb-6">
|
||||
Van{' '}
|
||||
<span className="text-coral-500">"dit moet ik uitzoeken"</span>
|
||||
{' '}naar{' '}
|
||||
<span className="text-teal-600">"dit werkt gewoon"</span>
|
||||
</h1>
|
||||
|
||||
{/* Subheadline */}
|
||||
<p className="text-xl md:text-2xl text-warm-600 mb-6 leading-relaxed">
|
||||
In 1 ochtend van nieuwsgierig naar praktisch aan de slag met Claude Code.
|
||||
Je gaat naar huis met je eigen werkende project.
|
||||
</p>
|
||||
|
||||
{/* Intro tekst */}
|
||||
<p className="text-lg text-warm-600 mb-8 leading-relaxed">
|
||||
Je hebt van Claude Code gehoord. Misschien zelfs al even mee gespeeld.
|
||||
Maar ergens tussen de installatie en dat eerste echte resultaat ben je
|
||||
blijven hangen. Herkenbaar? In deze hands-on workshop doorbreek je die drempel.
|
||||
Samen met maximaal 6 andere ondernemers ga je van nul naar een werkend project
|
||||
dat je direct kunt gebruiken in je business.
|
||||
</p>
|
||||
|
||||
{/* Workshop details - prominent weergave */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-10 p-6 bg-white/70 backdrop-blur-sm rounded-2xl border border-warm-200 shadow-sm">
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Calendar icon */}
|
||||
<div className="flex-shrink-0 w-12 h-12 bg-coral-100 rounded-xl flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-coral-600" 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>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-warm-500 font-medium uppercase tracking-wide">Datum</p>
|
||||
<p className="text-lg font-semibold text-warm-800">Vrijdag 6 maart 2026</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Clock icon */}
|
||||
<div className="flex-shrink-0 w-12 h-12 bg-teal-100 rounded-xl flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-teal-600" 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>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-warm-500 font-medium uppercase tracking-wide">Tijd</p>
|
||||
<p className="text-lg font-semibold text-warm-800">9:00 - 14:00</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Location icon */}
|
||||
<div className="flex-shrink-0 w-12 h-12 bg-coral-100 rounded-xl flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-coral-600" 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>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-warm-500 font-medium uppercase tracking-wide">Locatie</p>
|
||||
<p className="text-lg font-semibold text-warm-800">Utrecht</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
className="btn-primary inline-flex items-center gap-2"
|
||||
>
|
||||
Schrijf je in
|
||||
<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>
|
||||
</div>
|
||||
|
||||
{/* Rechter kolom: afbeelding placeholder */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="relative aspect-[4/3] bg-gradient-to-br from-warm-100 to-warm-200 rounded-2xl border-2 border-dashed border-warm-300 flex items-center justify-center">
|
||||
{/* Placeholder icon en tekst */}
|
||||
<div className="text-center text-warm-400">
|
||||
<svg className="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p className="text-lg font-medium">Workshop afbeelding</p>
|
||||
<p className="text-sm">Komt binnenkort</p>
|
||||
</div>
|
||||
{/* Decoratieve elementen */}
|
||||
<div className="absolute -top-4 -right-4 w-24 h-24 bg-coral-200 rounded-full blur-2xl opacity-50" />
|
||||
<div className="absolute -bottom-4 -left-4 w-20 h-20 bg-teal-200 rounded-full blur-2xl opacity-50" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Hero;
|
||||
72
src/components/PainPoints.jsx
Normal file
72
src/components/PainPoints.jsx
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* PainPoints.jsx - "Herkenbaar?" sectie
|
||||
*
|
||||
* Toont de frustraties/pijnpunten die de doelgroep herkent.
|
||||
* Elke pain point heeft een vraag-icoon voor visuele herkenning.
|
||||
*/
|
||||
|
||||
function PainPoints() {
|
||||
// De 4 pain points uit de content
|
||||
const painPoints = [
|
||||
"Je hebt YouTube tutorials gekeken, maar zodra je zelf begint loopt het anders dan in de video?",
|
||||
"Je weet dat AI tools je kunnen helpen, maar je hebt geen idee waar je moet beginnen met Claude Code?",
|
||||
"Je collega's of concurrenten werken al met AI, en jij bent nog aan het uitzoeken hoe het werkt?",
|
||||
"Je hebt weinig tijd om te experimenteren, en trial-and-error voelt als verspilling van kostbare uren?"
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section-alt">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-12">
|
||||
Herkenbaar?
|
||||
</h2>
|
||||
|
||||
{/* Pain points grid */}
|
||||
<div className="grid md:grid-cols-2 gap-6 max-w-4xl mx-auto mb-10">
|
||||
{painPoints.map((point, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex gap-4 p-6 bg-white rounded-xl border border-warm-200"
|
||||
>
|
||||
{/* Vraag icoon */}
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-10 h-10 rounded-full bg-coral-100 flex items-center justify-center">
|
||||
<svg
|
||||
className="w-5 h-5 text-coral-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pain point tekst */}
|
||||
<p className="text-warm-700 leading-relaxed">
|
||||
{point}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Afsluitende tekst */}
|
||||
<div className="max-w-2xl mx-auto text-center">
|
||||
<p className="text-lg text-warm-600 leading-relaxed">
|
||||
Da's frustrerend. Want je weet dat je sneller zou kunnen werken,
|
||||
betere output zou kunnen leveren. Maar die drempel...
|
||||
die blijft maar in de weg zitten.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default PainPoints;
|
||||
120
src/components/Pricing.jsx
Normal file
120
src/components/Pricing.jsx
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* Pricing.jsx - "Investering" sectie
|
||||
*
|
||||
* Toont de prijs, inclusief lijst en urgency element.
|
||||
* Bevat primaire CTA button naar inschrijving.
|
||||
*/
|
||||
|
||||
function Pricing() {
|
||||
// Wat is inbegrepen
|
||||
const included = [
|
||||
"Volledige workshop (9:00 - 14:00)",
|
||||
"Lunch en onbeperkt koffie/thee",
|
||||
"Persoonlijke begeleiding bij je project"
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section" id="inschrijven">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-12">
|
||||
Investering
|
||||
</h2>
|
||||
|
||||
{/* Pricing card */}
|
||||
<div className="max-w-xl mx-auto">
|
||||
<div className="card border-2 border-coral-200 relative overflow-hidden">
|
||||
{/* Decoratieve hoek */}
|
||||
<div
|
||||
className="absolute -top-10 -right-10 w-32 h-32 bg-coral-100 rounded-full blur-2xl opacity-60"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<div className="relative">
|
||||
{/* Prijs */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="flex items-baseline justify-center gap-2">
|
||||
<span className="text-5xl md:text-6xl font-display font-bold text-warm-900">
|
||||
€449
|
||||
</span>
|
||||
<span className="text-warm-500 text-lg">
|
||||
per persoon
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-warm-500 mt-1">
|
||||
excl. BTW
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Inclusief lijst */}
|
||||
<div className="mb-8">
|
||||
<h3 className="font-semibold text-warm-800 mb-4">
|
||||
Inbegrepen:
|
||||
</h3>
|
||||
<ul className="space-y-3">
|
||||
{included.map((item, index) => (
|
||||
<li key={index} className="flex gap-3">
|
||||
{/* Check icon */}
|
||||
<svg
|
||||
className="w-5 h-5 text-teal-500 flex-shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-warm-600">{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Urgency */}
|
||||
<div className="bg-coral-50 border border-coral-200 rounded-xl p-4 mb-6">
|
||||
<div className="flex gap-3">
|
||||
{/* Warning icon */}
|
||||
<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 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<div>
|
||||
<p className="font-semibold text-coral-700">
|
||||
Maximaal 7 deelnemers per workshop
|
||||
</p>
|
||||
<p className="text-coral-600 text-sm mt-1">
|
||||
Dit is bewust klein gehouden zodat iedereen persoonlijke aandacht krijgt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Button */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
className="btn-primary w-full text-center block"
|
||||
>
|
||||
Reserveer je plek
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Pricing;
|
||||
135
src/components/Program.jsx
Normal file
135
src/components/Program.jsx
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* Program.jsx - "Zo ziet je dag eruit" sectie
|
||||
*
|
||||
* Timeline/schedule layout met alle onderdelen van de workshop.
|
||||
* Lunch moment wordt visueel uitgelicht.
|
||||
*/
|
||||
|
||||
function Program() {
|
||||
// Programma onderdelen
|
||||
const schedule = [
|
||||
{
|
||||
time: "09:00",
|
||||
title: "Welkom en setup",
|
||||
description: "We zorgen dat iedereen een werkende Claude Code installatie heeft. Vastlopers lossen we direct samen op.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "09:30",
|
||||
title: "De basis begrijpen",
|
||||
description: "Je leert de interface, de belangrijkste commando's, en hoe Claude Code denkt. Geen droge theorie, maar direct toepassen.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "10:30",
|
||||
title: "Eerste hands-on oefening",
|
||||
description: "Je eerste echte project. Klein, overzichtelijk, en direct resultaat. Hier voel je hoe het werkt.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "11:30",
|
||||
title: "Lunch",
|
||||
description: "Wonders of Work heeft een heerlijke lunch voor ons klaarstaan. Tijd om bij te praten en te netwerken met de overige deelnemers.",
|
||||
isBreak: true
|
||||
},
|
||||
{
|
||||
time: "12:15",
|
||||
title: "Je eigen project starten",
|
||||
description: "Nu wordt het persoonlijk. Je werkt aan iets voor jouw business. Ik loop rond, help waar nodig, en zorg dat je niet vastloopt.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "13:15",
|
||||
title: "Agents en skills",
|
||||
description: "De krachtigere features. Hoe je Claude Code laat samenwerken met andere tools en hoe je complexere taken automatiseert.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "13:45",
|
||||
title: "Afronden en vervolgstappen",
|
||||
description: "We kijken naar wat je hebt gebouwd. Je krijgt concrete vervolgstappen die passen bij waar jij nu staat.",
|
||||
isBreak: false
|
||||
},
|
||||
{
|
||||
time: "14:00",
|
||||
title: "Einde",
|
||||
description: null,
|
||||
isBreak: false
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section-alt">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-4">
|
||||
Zo ziet je dag eruit
|
||||
</h2>
|
||||
<p className="text-warm-600 text-center mb-12 max-w-2xl mx-auto">
|
||||
Van 9:00 tot 14:00 werk je stap voor stap naar je eigen werkende project.
|
||||
</p>
|
||||
|
||||
{/* Timeline */}
|
||||
<div className="max-w-3xl mx-auto">
|
||||
{schedule.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`relative flex gap-6 ${index !== schedule.length - 1 ? 'pb-8' : ''}`}
|
||||
>
|
||||
{/* Timeline line */}
|
||||
{index !== schedule.length - 1 && (
|
||||
<div
|
||||
className={`absolute left-[39px] top-12 bottom-0 w-0.5 ${
|
||||
item.isBreak ? 'bg-teal-200' : 'bg-coral-200'
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Time badge */}
|
||||
<div className="flex-shrink-0 w-20">
|
||||
<span className={`inline-block px-3 py-1 rounded-lg text-sm font-semibold ${
|
||||
item.isBreak
|
||||
? 'bg-teal-100 text-teal-700'
|
||||
: 'bg-coral-100 text-coral-700'
|
||||
}`}>
|
||||
{item.time}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className={`flex-grow ${
|
||||
item.isBreak
|
||||
? 'bg-teal-50 border border-teal-200 rounded-xl p-4'
|
||||
: ''
|
||||
}`}>
|
||||
<h3 className={`font-display font-semibold text-lg ${
|
||||
item.isBreak ? 'text-teal-800' : 'text-warm-900'
|
||||
}`}>
|
||||
{item.title}
|
||||
{item.isBreak && (
|
||||
<span className="ml-2 inline-flex items-center">
|
||||
{/* Coffee icon */}
|
||||
<svg className="w-5 h-5 text-teal-600" 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>
|
||||
)}
|
||||
</h3>
|
||||
{item.description && (
|
||||
<p className={`mt-1 leading-relaxed ${
|
||||
item.isBreak ? 'text-teal-700' : 'text-warm-600'
|
||||
}`}>
|
||||
{item.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Program;
|
||||
108
src/components/StickyBar.jsx
Normal file
108
src/components/StickyBar.jsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* StickyBar.jsx - Sticky call-to-action bar
|
||||
*
|
||||
* Fixed aan onderkant (mobile) of bovenkant (desktop).
|
||||
* Compacte info: prijs + datum + CTA.
|
||||
* Verschijnt na scroll voorbij hero sectie.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
function StickyBar() {
|
||||
// State om te bepalen of de bar zichtbaar moet zijn
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
// Effect om scroll positie te monitoren
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
// Toon de bar na 600px scroll (ongeveer voorbij de hero)
|
||||
const scrollThreshold = 600;
|
||||
setIsVisible(window.scrollY > scrollThreshold);
|
||||
};
|
||||
|
||||
// Event listener toevoegen
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
|
||||
// Cleanup bij unmount
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
// Als niet zichtbaar, render niets
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Desktop versie - bovenkant */}
|
||||
<div className="hidden md:block fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-sm border-b border-warm-200 shadow-sm">
|
||||
<div className="container-page py-3">
|
||||
<div className="flex items-center justify-between">
|
||||
{/* Left: Info */}
|
||||
<div className="flex items-center gap-6">
|
||||
<span className="font-display font-semibold text-warm-900">
|
||||
Claude Code Workshop
|
||||
</span>
|
||||
<div className="flex items-center gap-4 text-sm text-warm-600">
|
||||
<span className="flex items-center gap-1">
|
||||
<svg className="w-4 h-4 text-coral-500" 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>
|
||||
6 maart 2026
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<svg className="w-4 h-4 text-coral-500" 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>
|
||||
Utrecht
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: Price + CTA */}
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="font-display font-bold text-xl text-warm-900">
|
||||
€449
|
||||
</span>
|
||||
<a
|
||||
href="#inschrijven"
|
||||
className="px-6 py-2 bg-coral-500 text-white font-semibold rounded-lg shadow-sm hover:bg-coral-600 transition-colors"
|
||||
>
|
||||
Inschrijven
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile versie - onderkant */}
|
||||
<div className="md:hidden fixed bottom-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-sm border-t border-warm-200 shadow-lg">
|
||||
<div className="px-4 py-3">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
{/* Left: Prijs en datum */}
|
||||
<div>
|
||||
<div className="font-display font-bold text-lg text-warm-900">
|
||||
€449
|
||||
</div>
|
||||
<div className="text-xs text-warm-500">
|
||||
6 maart 2026 | Utrecht
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: CTA */}
|
||||
<a
|
||||
href="#inschrijven"
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Spacer voor mobile om content niet te verbergen achter sticky bar */}
|
||||
<div className="md:hidden h-20" aria-hidden="true" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default StickyBar;
|
||||
94
src/components/Testimonials.jsx
Normal file
94
src/components/Testimonials.jsx
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Testimonials.jsx - "Wat deelnemers zeggen" sectie
|
||||
*
|
||||
* 3 placeholder testimonial cards met quote decoratie.
|
||||
* Bevat avatar met initialen, naam en functie.
|
||||
*/
|
||||
|
||||
function Testimonials() {
|
||||
// Placeholder testimonials - worden vervangen na eerste workshops
|
||||
const testimonials = [
|
||||
{
|
||||
quote: "[Quote over specifieke ervaring of doorbraak - aha-moment tijdens de workshop]",
|
||||
name: "Naam Deelnemer",
|
||||
role: "Functie / Bedrijf",
|
||||
initials: "ND"
|
||||
},
|
||||
{
|
||||
quote: "[Quote over praktische toepassing na de workshop - hoe het hun werk heeft verbeterd]",
|
||||
name: "Naam Deelnemer",
|
||||
role: "Functie / Bedrijf",
|
||||
initials: "ND"
|
||||
},
|
||||
{
|
||||
quote: "[Quote over de begeleiding en sfeer - persoonlijke aandacht en groepsdynamiek]",
|
||||
name: "Naam Deelnemer",
|
||||
role: "Functie / Bedrijf",
|
||||
initials: "ND"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="section">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-4">
|
||||
Wat deelnemers zeggen
|
||||
</h2>
|
||||
<p className="text-warm-500 text-center mb-12 italic">
|
||||
Testimonials worden toegevoegd na de eerste workshops
|
||||
</p>
|
||||
|
||||
{/* Testimonials grid */}
|
||||
<div className="grid md:grid-cols-3 gap-6 max-w-5xl mx-auto">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="card relative"
|
||||
>
|
||||
{/* Quote icon decoratie */}
|
||||
<div className="absolute -top-3 -left-2">
|
||||
<svg
|
||||
className="w-10 h-10 text-coral-200"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Quote tekst */}
|
||||
<blockquote className="mt-4 mb-6">
|
||||
<p className="text-warm-600 italic leading-relaxed">
|
||||
"{testimonial.quote}"
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
{/* Auteur info */}
|
||||
<div className="flex items-center gap-3 mt-auto">
|
||||
{/* Avatar met initialen */}
|
||||
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-coral-100 to-teal-100 flex items-center justify-center">
|
||||
<span className="text-warm-500 font-semibold">
|
||||
{testimonial.initials}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Naam en functie */}
|
||||
<div>
|
||||
<p className="font-semibold text-warm-900">
|
||||
{testimonial.name}
|
||||
</p>
|
||||
<p className="text-sm text-warm-500">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Testimonials;
|
||||
106
src/components/Trainer.jsx
Normal file
106
src/components/Trainer.jsx
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* Trainer.jsx - "Je trainer" sectie
|
||||
*
|
||||
* Bevat foto placeholder, naam en bio van Frank Meeuwsen.
|
||||
* Bio tekst is placeholder - moet nog ingevuld worden.
|
||||
*/
|
||||
|
||||
function Trainer() {
|
||||
return (
|
||||
<section className="section-alt">
|
||||
<div className="container-page">
|
||||
{/* Section title */}
|
||||
<h2 className="heading-2 text-center mb-12">
|
||||
Je trainer
|
||||
</h2>
|
||||
|
||||
{/* Trainer card */}
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="card flex flex-col md:flex-row gap-8 items-center md:items-start">
|
||||
{/* Foto placeholder */}
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-48 h-48 rounded-2xl bg-gradient-to-br from-coral-100 to-teal-100 flex items-center justify-center">
|
||||
{/* Placeholder icon */}
|
||||
<svg
|
||||
className="w-24 h-24 text-warm-300"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
{/* Placeholder tekst onder foto */}
|
||||
<p className="text-xs text-warm-400 text-center mt-2">
|
||||
[Foto toevoegen]
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Bio content */}
|
||||
<div className="flex-grow text-center md:text-left">
|
||||
<h3 className="heading-3 mb-4">
|
||||
Frank Meeuwsen
|
||||
</h3>
|
||||
|
||||
{/* Bio - placeholder tekst */}
|
||||
<div className="space-y-4 text-warm-600">
|
||||
<p className="leading-relaxed">
|
||||
<span className="text-warm-400 italic">
|
||||
[Korte bio - 2-3 zinnen over Frank's achtergrond met AI en Claude Code]
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p className="leading-relaxed">
|
||||
<span className="text-warm-400 italic">
|
||||
[Relevante ervaring/credentials - bijvoorbeeld hoeveel jaar ervaring,
|
||||
welke bedrijven geholpen, publicaties, etc.]
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p className="leading-relaxed">
|
||||
<span className="text-warm-400 italic">
|
||||
[Persoonlijke noot over waarom hij deze workshop geeft -
|
||||
wat drijft hem, wat wil hij deelnemers meegeven]
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Social links */}
|
||||
<div className="mt-6 flex gap-4 justify-center md:justify-start">
|
||||
<a
|
||||
href="https://www.linkedin.com/in/frankmeeuwsen"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-warm-400 hover:text-coral-500 transition-colors"
|
||||
aria-label="LinkedIn profiel"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://frankmeeuwsen.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-warm-400 hover:text-coral-500 transition-colors"
|
||||
aria-label="Website"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Trainer;
|
||||
19
src/components/index.js
Normal file
19
src/components/index.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Component index - centrale export voor alle componenten
|
||||
*
|
||||
* Maakt het mogelijk om meerdere componenten in één regel te importeren:
|
||||
* import { Hero, Benefits, FAQ } from './components';
|
||||
*/
|
||||
|
||||
export { default as Hero } from './Hero';
|
||||
export { default as PainPoints } from './PainPoints';
|
||||
export { default as Benefits } from './Benefits';
|
||||
export { default as Program } from './Program';
|
||||
export { default as ForWho } from './ForWho';
|
||||
export { default as Trainer } from './Trainer';
|
||||
export { default as Pricing } from './Pricing';
|
||||
export { default as Testimonials } from './Testimonials';
|
||||
export { default as FAQ } from './FAQ';
|
||||
export { default as FinalCTA } from './FinalCTA';
|
||||
export { default as Footer } from './Footer';
|
||||
export { default as StickyBar } from './StickyBar';
|
||||
104
src/index.css
Normal file
104
src/index.css
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
@apply scroll-smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-warm-50 text-warm-800 antialiased;
|
||||
}
|
||||
|
||||
/* Better focus states */
|
||||
*:focus-visible {
|
||||
@apply outline-none ring-4 ring-coral-500/50;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* Heading styles */
|
||||
.heading-hero {
|
||||
@apply font-display text-4xl md:text-5xl font-extrabold
|
||||
leading-tight tracking-tight text-warm-900;
|
||||
}
|
||||
|
||||
.heading-1 {
|
||||
@apply font-display text-3xl md:text-4xl font-bold
|
||||
leading-tight tracking-tight text-warm-900;
|
||||
}
|
||||
|
||||
.heading-2 {
|
||||
@apply font-display text-2xl md:text-3xl font-bold
|
||||
leading-snug text-warm-900;
|
||||
}
|
||||
|
||||
.heading-3 {
|
||||
@apply font-display text-xl md:text-2xl font-semibold
|
||||
leading-snug text-warm-800;
|
||||
}
|
||||
|
||||
/* Button variants */
|
||||
.btn-primary {
|
||||
@apply px-8 py-4
|
||||
bg-coral-500 text-white
|
||||
font-semibold text-lg
|
||||
rounded-xl
|
||||
shadow-lg shadow-coral-500/25
|
||||
hover:bg-coral-600 hover:shadow-xl hover:shadow-coral-500/30
|
||||
active:bg-coral-700 active:shadow-md
|
||||
transition-all duration-200
|
||||
focus:outline-none focus:ring-4 focus:ring-coral-500/50;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply px-6 py-3
|
||||
bg-white text-coral-600
|
||||
font-semibold
|
||||
rounded-xl
|
||||
border-2 border-coral-200
|
||||
hover:border-coral-300 hover:bg-coral-50
|
||||
active:bg-coral-100
|
||||
transition-all duration-200
|
||||
focus:outline-none focus:ring-4 focus:ring-coral-500/30;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
@apply px-4 py-2
|
||||
text-warm-700
|
||||
font-medium
|
||||
rounded-lg
|
||||
hover:bg-warm-100
|
||||
active:bg-warm-200
|
||||
transition-colors duration-150;
|
||||
}
|
||||
|
||||
/* Card variants */
|
||||
.card {
|
||||
@apply bg-white rounded-2xl border border-warm-200
|
||||
p-6 lg:p-8 shadow-sm
|
||||
hover:shadow-md hover:border-warm-300
|
||||
transition-all duration-200;
|
||||
}
|
||||
|
||||
.card-feature {
|
||||
@apply bg-gradient-to-br from-white to-coral-50/50
|
||||
rounded-2xl border border-coral-100
|
||||
p-6 lg:p-8 shadow-sm;
|
||||
}
|
||||
|
||||
/* Section */
|
||||
.section {
|
||||
@apply py-12 lg:py-20;
|
||||
}
|
||||
|
||||
.section-alt {
|
||||
@apply py-12 lg:py-20 bg-gradient-to-b from-warm-100/50 to-white;
|
||||
}
|
||||
|
||||
/* Container */
|
||||
.container-page {
|
||||
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
|
||||
}
|
||||
}
|
||||
19
src/main.jsx
Normal file
19
src/main.jsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom'
|
||||
import './index.css'
|
||||
import App from './App.jsx'
|
||||
import Privacy from './pages/Privacy.jsx'
|
||||
import Terms from './pages/Terms.jsx'
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/privacy" element={<Privacy />} />
|
||||
<Route path="/voorwaarden" element={<Terms />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
)
|
||||
113
src/pages/Privacy.jsx
Normal file
113
src/pages/Privacy.jsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Privacy.jsx - Privacybeleid pagina
|
||||
*
|
||||
* Standaard tekst die later aangepast moet worden.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Privacy() {
|
||||
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-3xl mx-auto">
|
||||
<h1 className="heading-hero mb-8">Privacybeleid</h1>
|
||||
|
||||
<div className="prose prose-warm max-w-none space-y-6 text-warm-700">
|
||||
<p className="text-lg text-warm-600">
|
||||
<em>Laatst bijgewerkt: [datum invullen]</em>
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">1. Inleiding</h2>
|
||||
<p>
|
||||
Dit privacybeleid beschrijft hoe Frank Meeuwsen (hierna "wij", "ons" of "onze")
|
||||
persoonsgegevens verzamelt, gebruikt en beschermt wanneer je onze website bezoekt
|
||||
of deelneemt aan onze workshops.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">2. Welke gegevens verzamelen wij?</h2>
|
||||
<p>Wij kunnen de volgende persoonsgegevens verzamelen:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Naam</li>
|
||||
<li>E-mailadres</li>
|
||||
<li>Bedrijfsnaam (indien van toepassing)</li>
|
||||
<li>Facturatiegegevens</li>
|
||||
<li>Eventuele andere informatie die je zelf aan ons verstrekt</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">3. Waarvoor gebruiken wij je gegevens?</h2>
|
||||
<p>Wij gebruiken je gegevens voor:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Het verwerken van je inschrijving voor een workshop</li>
|
||||
<li>Het versturen van praktische informatie over de workshop</li>
|
||||
<li>Het opstellen van facturen</li>
|
||||
<li>Het beantwoorden van je vragen</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">4. Bewaartermijn</h2>
|
||||
<p>
|
||||
Wij bewaren je gegevens niet langer dan noodzakelijk voor de doeleinden waarvoor
|
||||
ze zijn verzameld, of zo lang als wettelijk vereist is voor de belastingadministratie.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">5. Delen met derden</h2>
|
||||
<p>
|
||||
Wij verkopen of verhuren je gegevens niet aan derden. Wij kunnen gegevens delen
|
||||
met dienstverleners die ons helpen bij het uitvoeren van onze diensten, zoals
|
||||
betalingsverwerkers. Deze partijen mogen je gegevens alleen gebruiken in opdracht van ons.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">6. Je rechten</h2>
|
||||
<p>Je hebt het recht om:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Inzage te vragen in je persoonsgegevens</li>
|
||||
<li>Je gegevens te laten corrigeren of verwijderen</li>
|
||||
<li>Bezwaar te maken tegen verwerking van je gegevens</li>
|
||||
<li>Je gegevens over te dragen naar een andere partij</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">7. Contact</h2>
|
||||
<p>
|
||||
Heb je vragen over dit privacybeleid of wil je gebruik maken van je rechten?
|
||||
Neem dan contact met ons op via{' '}
|
||||
<a href="mailto:frank@frankmeeuwsen.com" className="text-coral-500 hover:text-coral-600">
|
||||
frank@frankmeeuwsen.com
|
||||
</a>.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">8. Wijzigingen</h2>
|
||||
<p>
|
||||
Wij behouden ons het recht voor dit privacybeleid te wijzigen. Wijzigingen worden
|
||||
op deze pagina gepubliceerd.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Simple 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 Privacy;
|
||||
129
src/pages/Terms.jsx
Normal file
129
src/pages/Terms.jsx
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* Terms.jsx - Algemene Voorwaarden pagina
|
||||
*
|
||||
* Standaard tekst die later aangepast moet worden.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function Terms() {
|
||||
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-3xl mx-auto">
|
||||
<h1 className="heading-hero mb-8">Algemene Voorwaarden</h1>
|
||||
|
||||
<div className="prose prose-warm max-w-none space-y-6 text-warm-700">
|
||||
<p className="text-lg text-warm-600">
|
||||
<em>Laatst bijgewerkt: [datum invullen]</em>
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 1 - Definities</h2>
|
||||
<p>In deze algemene voorwaarden wordt verstaan onder:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li><strong>Aanbieder:</strong> Frank Meeuwsen, gevestigd te [vestigingsplaats], KvK-nummer [nummer]</li>
|
||||
<li><strong>Deelnemer:</strong> de natuurlijke of rechtspersoon die deelneemt aan een workshop</li>
|
||||
<li><strong>Workshop:</strong> de Claude Code Hands-on Sessie zoals aangeboden op deze website</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 2 - Toepasselijkheid</h2>
|
||||
<p>
|
||||
Deze algemene voorwaarden zijn van toepassing op alle aanbiedingen, overeenkomsten en
|
||||
leveringen van workshops door de aanbieder.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 3 - Inschrijving</h2>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Inschrijving voor een workshop geschiedt via het inschrijfformulier op de website.</li>
|
||||
<li>Na inschrijving ontvang je een bevestiging per e-mail.</li>
|
||||
<li>De inschrijving is definitief na ontvangst van de betaling.</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 4 - Betaling</h2>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>De workshopprijs is €449,- excl. BTW per deelnemer.</li>
|
||||
<li>Betaling dient vooraf te geschieden via de aangegeven betaalmethode.</li>
|
||||
<li>Na ontvangst van de betaling ontvang je een factuur.</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 5 - Annulering door deelnemer</h2>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Bij annulering tot 14 dagen voor de workshop: volledige restitutie.</li>
|
||||
<li>Bij annulering tussen 14 en 7 dagen voor de workshop: 50% restitutie.</li>
|
||||
<li>Bij annulering binnen 7 dagen voor de workshop: geen restitutie.</li>
|
||||
<li>Je mag altijd een vervangende deelnemer aanmelden.</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 6 - Annulering door aanbieder</h2>
|
||||
<p>
|
||||
De aanbieder behoudt zich het recht voor een workshop te annuleren bij onvoldoende
|
||||
deelnemers of overmacht. In dat geval ontvang je het volledige bedrag terug of kun
|
||||
je kosteloos verplaatsen naar een volgende datum.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 7 - Aansprakelijkheid</h2>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>De aanbieder is niet aansprakelijk voor schade die voortvloeit uit het gebruik van de tijdens de workshop opgedane kennis.</li>
|
||||
<li>De aanbieder is niet aansprakelijk voor verlies, diefstal of beschadiging van persoonlijke eigendommen tijdens de workshop.</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 8 - Intellectueel eigendom</h2>
|
||||
<p>
|
||||
Alle door de aanbieder verstrekte materialen zijn uitsluitend bedoeld voor eigen
|
||||
gebruik van de deelnemer. Het is niet toegestaan deze materialen te delen,
|
||||
verveelvoudigen of commercieel te gebruiken zonder schriftelijke toestemming.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 9 - Privacy</h2>
|
||||
<p>
|
||||
De aanbieder verwerkt persoonsgegevens conform het privacybeleid zoals beschreven
|
||||
op{' '}
|
||||
<Link to="/privacy" className="text-coral-500 hover:text-coral-600">
|
||||
de privacy pagina
|
||||
</Link>.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 10 - Klachten</h2>
|
||||
<p>
|
||||
Klachten over de workshop dienen binnen 14 dagen na afloop schriftelijk te worden
|
||||
ingediend via{' '}
|
||||
<a href="mailto:frank@frankmeeuwsen.com" className="text-coral-500 hover:text-coral-600">
|
||||
frank@frankmeeuwsen.com
|
||||
</a>.
|
||||
</p>
|
||||
|
||||
<h2 className="heading-3 mt-8">Artikel 11 - Toepasselijk recht</h2>
|
||||
<p>
|
||||
Op deze algemene voorwaarden en alle overeenkomsten is Nederlands recht van toepassing.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Simple 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 Terms;
|
||||
69
tailwind.config.js
Normal file
69
tailwind.config.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
coral: {
|
||||
50: '#FFF5F3',
|
||||
100: '#FFE8E3',
|
||||
200: '#FFD0C7',
|
||||
300: '#FFA99A',
|
||||
400: '#FF7D66',
|
||||
500: '#F25C3D',
|
||||
600: '#D94425',
|
||||
700: '#B5351A',
|
||||
800: '#912B16',
|
||||
900: '#6B2213',
|
||||
},
|
||||
teal: {
|
||||
50: '#F0FDFA',
|
||||
100: '#CCFBF1',
|
||||
200: '#99F6E4',
|
||||
300: '#5EEAD4',
|
||||
400: '#2DD4BF',
|
||||
500: '#14B8A6',
|
||||
600: '#0D9488',
|
||||
700: '#0F766E',
|
||||
800: '#115E59',
|
||||
900: '#134E4A',
|
||||
},
|
||||
warm: {
|
||||
50: '#FDFCFB',
|
||||
100: '#F9F7F5',
|
||||
200: '#F0EDEA',
|
||||
300: '#E0DBD5',
|
||||
400: '#C4BBB2',
|
||||
500: '#A39990',
|
||||
600: '#7A7067',
|
||||
700: '#5C544C',
|
||||
800: '#3D3833',
|
||||
900: '#1F1C19',
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
display: ['Bricolage Grotesque', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
fontSize: {
|
||||
'hero': ['3rem', { lineHeight: '1.1', letterSpacing: '-0.02em' }],
|
||||
},
|
||||
boxShadow: {
|
||||
'coral': '0 10px 15px -3px rgb(242 92 61 / 0.25)',
|
||||
'coral-lg': '0 20px 25px -5px rgb(242 92 61 / 0.3)',
|
||||
},
|
||||
borderRadius: {
|
||||
'4xl': '2rem',
|
||||
},
|
||||
spacing: {
|
||||
'18': '4.5rem',
|
||||
'22': '5.5rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
7
vite.config.js
Normal file
7
vite.config.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
Loading…
Reference in a new issue