import React, { useMemo, useState } from "react"; import { ChevronRight, CalendarDays, Dumbbell, Flame, Home, LineChart, PlayCircle, Search, Sparkles, Target, Trophy, Plus, Clock3, Activity, BookOpen, Save, } from "lucide-react"; import { ResponsiveContainer, LineChart as ReLineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, } from "recharts"; const weeklyPlan = [ { day: "Maandag", type: "football", title: "Voetbal", accent: "emerald" }, { day: "Dinsdag", type: "push", title: "Gym • Push", accent: "rose" }, { day: "Woensdag", type: "football", title: "Voetbal", accent: "emerald" }, { day: "Donderdag", type: "legs", title: "Gym • Benen", accent: "amber" }, { day: "Vrijdag", type: "pull", title: "Gym • Pull", accent: "sky" }, { day: "Zaterdag", type: "football", title: "Wedstrijd", accent: "violet" }, { day: "Zondag", type: "optional", title: "Optioneel herstel / lichte gym", accent: "slate" }, ]; const workoutLibrary = { football: { title: "Full Body Light", subtitle: "Licht, atletisch en slim rondom voetbalbelasting.", note: "Gebruik dit als een korte onderhouds-workout: technisch strak, weinig spierpijn, en niet tot falen.", exercises: [ { name: "Goblet Squat", sets: "2-3 × 8-10", reps: "8-10", video: "https://www.youtube.com/results?search_query=goblet+squat+how+to", explanation: "Goede full-body start voor benen en core zonder zware vermoeidheid. Denk aan houding, diepe controle en rustige herhalingen.", tips: ["Hou je borst trots", "Zak gecontroleerd", "Blijf uit de pijnzone"], }, { name: "Push-Up", sets: "2-3 × 8-15", reps: "8-15", video: "https://www.youtube.com/results?search_query=push+up+how+to", explanation: "Simpele horizontale duw om borst en triceps bij te houden. Jeff-achtig principe: kwaliteit boven ego, volle range of motion.", tips: ["Strakke plank positie", "Ellebogen licht schuin", "Rustig zakken"], }, { name: "Cable Row / Band Row", sets: "2-3 × 10-12", reps: "10-12", video: "https://www.youtube.com/results?search_query=seated+cable+row+how+to", explanation: "Een lichte trekbeweging houdt je rug actief en helpt houding en schouderbalans, zonder je wedstrijdbewegingen te slopen.", tips: ["Schouderbladen naar achter", "Niet gooien met je romp", "Voel de stretch"], }, { name: "Plank", sets: "2-3 × 30-45 sec", reps: "30-45 sec", video: "https://www.youtube.com/results?search_query=plank+how+to", explanation: "Core-stabiliteit helpt bij sport, sprinten en contactmomenten. Houd dit kort en strak.", tips: ["Ribben omlaag", "Bilspieren aanspannen", "Geen doorgezakte onderrug"], }, ], }, push: { title: "Push", subtitle: "Borst, schouders en triceps met focus op progressieve overload.", note: "Start met compounds, eindig met isolatie. Werk met gecontroleerde uitvoeringen en noteer je gewicht per set.", exercises: [ { name: "Barbell Bench Press", sets: "3-4 × 5-8", reps: "5-8", video: "https://www.youtube.com/results?search_query=barbell+bench+press+how+to", explanation: "Jeff Nippard-stijl hoofdbeweging voor borstkracht en massa. Stabiele setup, volledige controle en alleen load verhogen als je techniek strak blijft.", tips: ["Schouderbladen vast", "Bar naar borst met controle", "Explosief omhoog"], }, { name: "Incline Dumbbell Press", sets: "3 × 8-10", reps: "8-10", video: "https://www.youtube.com/results?search_query=incline+dumbbell+press+how+to", explanation: "Pakt bovenborst en voorste schouderkop goed mee. Houd spanning constant en gebruik een incline die je goed voelt.", tips: ["Elleboog onder controle", "Diepe stretch", "Geen zwaaien"], }, { name: "Seated Shoulder Press", sets: "3 × 6-10", reps: "6-10", video: "https://www.youtube.com/results?search_query=seated+shoulder+press+how+to", explanation: "Sterke verticale press voor delts en triceps. Ga niet maximaal forceren; laat de reps technisch netjes blijven.", tips: ["Core aangespannen", "Ribben laag", "Volledige maar veilige ROM"], }, { name: "Lateral Raises", sets: "3 × 12-20", reps: "12-20", video: "https://www.youtube.com/results?search_query=lateral+raise+how+to", explanation: "Zijschouders reageren vaak goed op hogere reps en goede spanning. Hier wil je strakke herhalingen, geen ego.", tips: ["Elleboog iets hoger", "Rustig omlaag", "Voel de zijkant van je schouder"], }, { name: "Cable Tricep Pushdown", sets: "3 × 10-15", reps: "10-15", video: "https://www.youtube.com/results?search_query=cable+tricep+pushdown+how+to", explanation: "Goede isolatie voor extra tricepsvolume. Fixeer je ellebogen en knijp onderin even hard aan.", tips: ["Ellebogen stil", "Volledig strekken", "Niet leunen"], }, ], }, legs: { title: "Benen", subtitle: "Sterke benen voor voetbal en spiergroei, maar slim gedoseerd.", note: "Leg day moet je beter maken, niet slopen. Gebruik kwaliteit, volledige controle en geen slordige reps.", exercises: [ { name: "Back Squat", sets: "3-4 × 4-8", reps: "4-8", video: "https://www.youtube.com/results?search_query=back+squat+how+to", explanation: "De grote compound voor quads, glutes en core. Jeff-achtig principe: eerst techniek, dan pas gewicht.", tips: ["Voeten stevig", "Controle in de diepte", "Romp strak"], }, { name: "Romanian Deadlift", sets: "3 × 6-10", reps: "6-10", video: "https://www.youtube.com/results?search_query=romanian+deadlift+how+to", explanation: "Top voor hamstrings en glutes. Denk aan hip hinge en houd de bar dicht langs je lichaam.", tips: ["Knieën licht gebogen", "Heupen naar achter", "Niet rond trekken met je onderrug"], }, { name: "Leg Press", sets: "3 × 10-15", reps: "10-15", video: "https://www.youtube.com/results?search_query=leg+press+how+to", explanation: "Veel quad volume met minder techniekstress dan squat. Perfect als extra hypertrophy-prikkel.", tips: ["Heupen op de bank", "Volledige controle", "Niet te kort bewegen"], }, { name: "Leg Curl", sets: "3 × 10-15", reps: "10-15", video: "https://www.youtube.com/results?search_query=leg+curl+how+to", explanation: "Hamstring-isolatie helpt balans en blessurepreventie. Hou de reps strak en gecontroleerd.", tips: ["Volledige stretch", "Bovenin knijpen", "Geen heupen gooien"], }, { name: "Standing Calf Raise", sets: "3-4 × 12-20", reps: "12-20", video: "https://www.youtube.com/results?search_query=standing+calf+raise+how+to", explanation: "Kuiten reageren vaak goed op hogere reps en grote stretch. Neem hier je tijd en gebruik volledige range.", tips: ["Onderin diep", "Bovenin hard aanspannen", "Rustig tempo"], }, ], }, pull: { title: "Pull", subtitle: "Rug, achterste schouders en biceps.", note: "Combineer een verticale trek met horizontale trek en eindig met rear delts en biceps.", exercises: [ { name: "Pull-ups / Lat Pulldown", sets: "3-4 × 6-10", reps: "6-10", video: "https://www.youtube.com/results?search_query=pull+up+how+to+lat+pulldown+how+to", explanation: "Sterke vertikale trek voor lats. Kies de variant waarmee je strak en progressief kunt trainen.", tips: ["Ellebogen naar je heupen", "Volledige stretch", "Niet zwaaien"], }, { name: "Barbell Row", sets: "3 × 6-10", reps: "6-10", video: "https://www.youtube.com/results?search_query=barbell+row+how+to", explanation: "Sterke horizontale trek voor rugmassa. Houd je torso stabiel en trek consistent.", tips: ["Hinge vastzetten", "Trek naar onderbuik", "Geen momentum"], }, { name: "Seated Cable Row", sets: "3 × 8-12", reps: "8-12", video: "https://www.youtube.com/results?search_query=seated+cable+row+how+to", explanation: "Fijne oefening voor constante spanning. Goed voor extra rugvolume met een gecontroleerde uitvoering.", tips: ["Lang uitrekken", "Middenrug voelen", "Elke rep strak"], }, { name: "Face Pull", sets: "3 × 12-20", reps: "12-20", video: "https://www.youtube.com/results?search_query=face+pull+how+to", explanation: "Rear delt- en schoudergezondheidsoefening. Licht gewicht, goede lijn en nette reps.", tips: ["Trek naar ooghoogte", "Ellebogen hoog", "Rustig terug"], }, { name: "Dumbbell Curl", sets: "3 × 8-12", reps: "8-12", video: "https://www.youtube.com/results?search_query=dumbbell+bicep+curl+how+to", explanation: "Klassieke biceps-builder. Hou de schouders rustig en maak de volledige beweging af.", tips: ["Ellebogen stil", "Volledige extensie", "Niet gooien"], }, ], }, optional: { title: "Herstel / lichte gym", subtitle: "Alleen doen als je fris bent.", note: "Deze dag is optioneel. Denk aan mobility, core, licht bovenlichaam of zwakke punten.", exercises: [ { name: "Mobility Flow", sets: "10-15 min", reps: "-", video: "https://www.youtube.com/results?search_query=mobility+flow+warm+up", explanation: "Maak je lichaam los en herstel sneller. Houd het licht en rustig.", tips: ["Adem rustig", "Werk door de heupen en enkels", "Geen intensiteit"], }, { name: "Core Circuit", sets: "2-3 rondes", reps: "8-15", video: "https://www.youtube.com/results?search_query=core+workout+basic", explanation: "Korte core-sessie voor stabiliteit en sportcontrole. Compact en niet slopend.", tips: ["Kwaliteit boven volume", "Rustig tempo", "Blijf gecontroleerd"], }, ], }, }; const tabs = [ { id: "home", label: "Home", icon: Home }, { id: "schema", label: "Schema", icon: CalendarDays }, { id: "progress", label: "Progress", icon: LineChart }, ]; const accentMap = { emerald: "from-emerald-500/20 to-emerald-400/5 border-emerald-400/20", rose: "from-rose-500/20 to-rose-400/5 border-rose-400/20", amber: "from-amber-500/20 to-amber-400/5 border-amber-400/20", sky: "from-sky-500/20 to-sky-400/5 border-sky-400/20", violet: "from-violet-500/20 to-violet-400/5 border-violet-400/20", slate: "from-slate-500/20 to-slate-400/5 border-white/10", }; export default function App() { const [tab, setTab] = useState("home"); const [selectedDay, setSelectedDay] = useState(weeklyPlan[1]); const [selectedExercise, setSelectedExercise] = useState("Barbell Bench Press"); const [entries, setEntries] = useState([ { exercise: "Barbell Bench Press", weight: 70, reps: 8, date: "2026-03-18", day: "Dinsdag" }, { exercise: "Back Squat", weight: 90, reps: 5, date: "2026-03-19", day: "Donderdag" }, { exercise: "Pull-ups / Lat Pulldown", weight: 55, reps: 8, date: "2026-03-20", day: "Vrijdag" }, ]); const selectedWorkout = workoutLibrary[selectedDay.type]; const selectedExercises = selectedWorkout.exercises; const allExerciseNames = useMemo(() => { const names = []; Object.values(workoutLibrary).forEach((group) => { group.exercises.forEach((ex) => names.push(ex.name)); }); return names; }, []); const saveLog = (exercise, weight, reps, day) => { if (!weight || !reps) return; setEntries((prev) => [ { exercise, weight: Number(weight), reps: Number(reps), date: new Date().toISOString().slice(0, 10), day, }, ...prev, ]); }; const weeklyStats = useMemo(() => { const totalSets = entries.length; const avgWeight = totalSets ? Math.round(entries.reduce((sum, e) => sum + e.weight, 0) / totalSets) : 0; const bestEntry = entries.reduce((best, current) => (current.weight * current.reps > best.weight * best.reps ? current : best), entries[0] || { weight: 0, reps: 0, exercise: "-" }); return { totalSets, avgWeight, bestEntry }; }, [entries]); const totalVolumeByDate = useMemo(() => { const grouped = {}; entries.forEach((e) => { if (!grouped[e.date]) grouped[e.date] = 0; grouped[e.date] += e.weight * e.reps; }); return Object.entries(grouped) .sort(([a], [b]) => a.localeCompare(b)) .map(([date, volume], index) => ({ date, volume, idx: index + 1 })); }, [entries]); const selectedExerciseProgress = useMemo(() => { return entries .filter((e) => e.exercise === selectedExercise) .sort((a, b) => a.date.localeCompare(b.date)) .map((e, index) => ({ session: index + 1, weight: e.weight, reps: e.reps, date: e.date, volume: e.weight * e.reps, })); }, [entries, selectedExercise]); const recentLogs = useMemo(() => entries.slice(0, 8), [entries]); const dayColorClass = accentMap[selectedDay.accent] || accentMap.slate; return (
Training dashboard

Voetbal + Gym App

Overzichtelijk schema, duidelijke oefeningsuitleg en progress-tracking in één app.

Jeff Nippard geïnspireerd
{tab === "home" && (

Deze week in één oogopslag

Je week is verdeeld zodat voetbal en kracht elkaar zo min mogelijk in de weg zitten.

Korte uitleg

De app gebruikt een duidelijke weekindeling: voetbaldagen krijgen een lichte full-body sessie, de gymdagen krijgen een echte push / legs / pull-opbouw, en progress wordt gelogd per oefening.

Vandaag / volgende training

Tik op een dag om het detailplan te openen.

{weeklyPlan.map((day) => ( ))}
)} {tab === "schema" && (

Weekschema

Kies een dag en zie direct de oefeningen, uitleg en een veld om je gewicht te loggen.

{weeklyPlan.map((day) => ( ))}
{selectedDay.day}

{selectedWorkout.title}

{selectedWorkout.subtitle}

{selectedDay.type === "football" ? : }

{selectedWorkout.note}

{selectedExercises.map((exercise) => ( ))}
)} {tab === "progress" && (

Totale groei

Volume per dag: gewicht × reps, samengevoegd per datum.

Per oefening

Kies een oefening om je progressie per lift te zien.

Recente logs

{recentLogs.length === 0 ? ( ) : ( recentLogs.map((entry, index) => (
{entry.exercise}
{entry.day} • {entry.date}
{entry.weight} kg
{entry.reps} reps
)) )}

Praktische richtlijn

Als je oefening soepel voelt en je reps omhoog gaan, zit je goed. Als je techniek instort, verhoog je nog niet.

Voor Jeff Nippard-stijl progressie: houd je oefening consistent, verhoog gewicht of reps langzaam en log alles netjes.

Voor voetbalweken is het slim om een paar herhalingen in reserve te houden op de zware dagen, vooral richting wedstrijd.

)}
); } function ExerciseCard({ exercise, dayLabel, onSave }) { const [weight, setWeight] = useState(""); const [reps, setReps] = useState(""); const [showDetails, setShowDetails] = useState(false); return (

{exercise.name}

{exercise.sets}

{exercise.explanation}

Video
{showDetails && (
Jeff-inspired aandachtspunten
)}
setWeight(e.target.value)} placeholder="Gewicht (kg)" className="w-full rounded-[18px] border border-white/10 bg-white/5 px-4 py-3 outline-none placeholder:text-white/30" /> setReps(e.target.value)} placeholder="Reps" className="w-full rounded-[18px] border border-white/10 bg-white/5 px-4 py-3 outline-none placeholder:text-white/30" />
{dayLabel}
); } function KpiCard({ label, value, icon: Icon }) { return (
{label}
{value}
); } function EmptyState({ title, text }) { return (
{title}

{text}

); }