import { motion } from "framer-motion";
import { useEffect, useState } from "react";
type PageKey =
| "home"
| "programmering"
| "programmas"
| "gedraaid"
| "luister-live"
| "over-ons"
| "contact";
const navigation: Array<{ key: PageKey; label: string }> = [
{ key: "home", label: "Home" },
{ key: "programmering", label: "Programmering" },
{ key: "programmas", label: "Programma's" },
{ key: "gedraaid", label: "Gedraaid" },
{ key: "luister-live", label: "Luister Live" },
{ key: "over-ons", label: "Over Ons" },
{ key: "contact", label: "Contact" },
];
const programmeringWeek = [
{ start: "06:00", eind: "09:00", titel: "Goedemorgen Meeuwbeemd" },
{ start: "09:00", eind: "12:00", titel: "Arbeidsvitaminen 79-89" },
{ start: "12:00", eind: "14:00", titel: "Lunch op 3" },
{ start: "14:00", eind: "16:00", titel: "Middagmix op 3" },
{ start: "16:00", eind: "18:00", titel: "De Avondspits" },
{ start: "18:00", eind: "20:00", titel: "Top 40 Terugblik" },
{ start: "20:00", eind: "22:00", titel: "Vinylavond 80s" },
{ start: "22:00", eind: "24:00", titel: "Nacht op 3" },
];
const programmeringWeekend = [
{ start: "06:00", eind: "09:00", titel: "Weekend Wekker" },
{ start: "09:00", eind: "12:00", titel: "Koffie en Classics" },
{ start: "12:00", eind: "14:00", titel: "Weekendmix" },
{ start: "14:00", eind: "16:00", titel: "Verzoekplaten Parade" },
{ start: "16:00", eind: "18:00", titel: "Nederpop Selectie" },
{ start: "18:00", eind: "20:00", titel: "Gouwe Ouwe Top 80" },
{ start: "20:00", eind: "22:00", titel: "Avondconcert" },
];
const programmas = [
{
naam: "Goedemorgen Meeuwbeemd",
tijd: "Ma t/m vr 06:00 - 09:00",
beschrijving: "Vroege ochtendstart met nieuws, serviceberichten en bekende pop uit 79-89.",
},
{
naam: "Arbeidsvitaminen 79-89",
tijd: "Maandag t/m vrijdag 09:00 - 12:00",
beschrijving: "Non-stop pop en classics uit 1979 tot 1989, precies zoals vroeger op de werkvloer.",
},
{
naam: "Lunch op 3",
tijd: "Ma t/m vr 12:00 - 14:00",
beschrijving: "Luchtige lunchradio met herkenbare jingles, korte items en tijdloze hits.",
},
{
naam: "Middagmix op 3",
tijd: "Dagelijks 14:00 - 16:00",
beschrijving: "De beste mix van Nederlandse en internationale radiohits uit de jaren 80.",
},
{
naam: "De Avondspits",
tijd: "Dagelijks 16:00 - 18:00",
beschrijving: "Tempo, verkeer en meezingers voor het einde van de middag.",
},
{
naam: "Top 40 Terugblik",
tijd: "Dagelijks 18:00 - 20:00",
beschrijving: "De grootste hits uit de Nederlandse Top 40 van de jaren 80, met radiofragmenten en intro's.",
},
{
naam: "Vinylavond 80s",
tijd: "Dagelijks 20:00 - 22:00",
beschrijving: "Een warme avondplaat met new wave, synthpop en soft rock van 1979 tot 1989.",
},
{
naam: "Nacht op 3",
tijd: "Ma t/m vr 22:00 - 24:00",
beschrijving: "Rustige nachturen met late-night classics en vertrouwde stemvoering in retro radio-stijl.",
},
{
naam: "Weekend Wekker",
tijd: "Za en zo 06:00 - 09:00",
beschrijving: "Ontspannen weekendstart met warme oldies en vriendelijke presentatie.",
},
{
naam: "Koffie en Classics",
tijd: "Za en zo 09:00 - 12:00",
beschrijving: "Drie uur lang rustige classics, luisteraarsgroeten en vertrouwde sfeer.",
},
{
naam: "Verzoekplaten Parade",
tijd: "Za en zo 14:00 - 16:00",
beschrijving: "Populaire verzoekplaten van bewoners en familie, met korte introducties.",
},
];
const laatstGedraaid = [
{
tijd: "14:52",
titel: "Ti Amo",
artiest: "Umberto Tozzi",
album: "Ti Amo",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/6/6e/Umberto_Tozzi_Ti_Amo.jpg/320px-Umberto_Tozzi_Ti_Amo.jpg",
},
{
tijd: "14:48",
titel: "Volare (Nel Blu Dipinto Di Blu)",
artiest: "Domenico Modugno",
album: "Nel Blu Dipinto Di Blu",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/d/d4/Nel_Blu_Dipinto_Di_Blu_cover.jpg/320px-Nel_Blu_Dipinto_Di_Blu_cover.jpg",
},
{
tijd: "14:44",
titel: "Gloria",
artiest: "Umberto Tozzi",
album: "Gloria",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/0/0f/Umberto_Tozzi_Gloria.jpg/320px-Umberto_Tozzi_Gloria.jpg",
},
{
tijd: "14:39",
titel: "Sarà perché ti amo",
artiest: "Ricchi e Poveri",
album: "E penso a te",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/e/e6/Sara_perche_ti_amo.jpg/320px-Sara_perche_ti_amo.jpg",
},
{
tijd: "14:35",
titel: "Felicità",
artiest: "Al Bano & Romina Power",
album: "Felicità",
cover: "https://upload.wikimedia.org/wikipedia/en/thumb/1/15/Felicita_cover.jpg/320px-Felicita_cover.jpg",
},
];
const fallbackCover =
"https://images.unsplash.com/photo-1511379938547-c1f69419868d?auto=format&fit=crop&w=300&q=80";
const streamUrl = "https://reteradioazzurra.radioca.st/stream";
const logoUrl = "/images/meeuwbeemd-logo.png";
function getHashPage(): PageKey {
const hash = window.location.hash.replace("#", "") as PageKey;
return navigation.some((item) => item.key === hash) ? hash : "home";
}
export default function App() {
const [activePage, setActivePage] = useState<PageKey>(getHashPage());
useEffect(() => {
const onHashChange = () => setActivePage(getHashPage());
window.addEventListener("hashchange", onHashChange);
return () => window.removeEventListener("hashchange", onHashChange);
}, []);
return (
<div className="min-h-screen bg-[#f2ebd8] text-[#103a5b]">
<header className="sticky top-0 z-20 border-b border-[#d1a24b]/40 bg-[#103a5b]/95 backdrop-blur">
<div className="mx-auto flex max-w-6xl flex-wrap items-center justify-between gap-4 px-6 py-3">
<a href="#home" className="flex items-center gap-3">
<img src={logoUrl} alt="Meeuwbeemd Radio logo" className="h-12 w-12 rounded-full border border-[#d1a24b]/60" />
<span className="text-lg font-extrabold tracking-wide text-[#f5ecd7] sm:text-2xl">MEEUWBEEMD RADIO</span>
</a>
<nav className="flex flex-wrap gap-4 text-sm font-semibold text-[#f5ecd7]">
{navigation.map((item) => (
<a
key={item.key}
href={`#${item.key}`}
className={`transition-colors hover:text-[#d7a84a] ${activePage === item.key ? "text-[#d7a84a] underline underline-offset-4" : ""}`}
>
{item.label}
</a>
))}
</nav>
</div>
</header>
<main className="mx-auto max-w-6xl px-6 py-12">
{activePage === "home" && <HomePage />}
{activePage === "programmering" && <ProgrammeringPage />}
{activePage === "programmas" && <ProgrammasPage />}
{activePage === "gedraaid" && <GedraaidPage />}
{activePage === "luister-live" && <LuisterLivePage />}
{activePage === "over-ons" && <OverOnsPage />}
{activePage === "contact" && <ContactPage />}
</main>
<footer className="bg-[#103a5b] px-6 py-10 text-center text-[#f5ecd7]">
<img src={logoUrl} alt="Meeuwbeemd Radio logo" className="mx-auto h-20 w-20 rounded-full border-2 border-[#d1a24b]/80" />
<p className="mt-4 text-xl font-semibold text-[#f5ecd7]">Meeuwbeemd Radio - Muziek en informatie voor elke dag</p>
<p className="mt-2 text-base text-[#e7d8b7]">Copyright Verzorgingshuis Meeuwbeemd</p>
</footer>
</div>
);
}
function HomePage() {
return (
<section className="relative overflow-hidden rounded-2xl border border-[#d1a24b]/30 bg-gradient-to-b from-[#153f61] via-[#103a5b] to-[#0d314d]">
<motion.div
className="absolute inset-0"
animate={{ backgroundPositionX: ["0%", "100%", "0%"] }}
transition={{ duration: 26, repeat: Infinity, ease: "easeInOut" }}
style={{
backgroundImage:
"radial-gradient(circle at 10% 20%, rgba(209,162,75,0.18) 0 8%, transparent 9%), radial-gradient(circle at 70% 25%, rgba(209,162,75,0.13) 0 11%, transparent 12%), radial-gradient(circle at 30% 80%, rgba(245,236,215,0.1) 0 9%, transparent 10%)",
backgroundSize: "760px 360px",
}}
/>
<div className="relative mx-auto flex min-h-[72vh] max-w-4xl flex-col items-center justify-center gap-8 px-6 py-14 text-center">
<motion.img
src={logoUrl}
alt="Meeuwbeemd Radio"
className="h-44 w-44 rounded-full border-4 border-[#d1a24b]/70 shadow-[0_18px_40px_rgba(0,0,0,0.28)] md:h-56 md:w-56"
initial={{ opacity: 0, scale: 0.85, y: 16 }}
animate={{ opacity: 1, scale: 1, y: [0, -5, 0] }}
transition={{ duration: 0.9, y: { duration: 4.5, repeat: Infinity, ease: "easeInOut" } }}
/>
<motion.p
initial={{ opacity: 0, y: 18 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-base font-semibold tracking-[0.2em] text-[#d7a84a]"
>
MEEUWBEEMD RADIO
</motion.p>
<motion.h1
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.1 }}
className="text-4xl leading-tight font-extrabold text-[#f5ecd7] md:text-6xl"
>
Muziek en informatie voor elke dag
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.2 }}
className="max-w-2xl text-lg text-[#e9dbc0]"
>
Het vertrouwde geluid voor bewoners en bezoekers. Rust, herkenning en gezelligheid in elk uur van de dag.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.3 }}
className="flex flex-wrap items-center justify-center gap-4"
>
<a
href="#luister-live"
className="rounded-xl bg-[#d1a24b] px-10 py-4 text-xl font-bold text-[#103a5b] shadow-[0_8px_25px_rgba(0,0,0,0.28)] transition hover:scale-[1.03] hover:bg-[#e2b154]"
>
Luister Live
</a>
<a
href="#programmering"
className="rounded-xl border-2 border-[#d1a24b] bg-transparent px-8 py-4 text-xl font-bold text-[#f5ecd7] transition hover:bg-[#d1a24b]/10"
>
Bekijk Programmering
</a>
</motion.div>
</div>
</section>
);
}
function ProgrammeringPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Vandaag op de radio</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Programmering in Hilversum 3 stijl uit de jaren 1979 tot 1989.
</p>
<div className="mt-10 grid gap-8 lg:grid-cols-2">
<div>
<h3 className="text-2xl font-bold text-[#103a5b]">Doordeweeks (ma-vr) 06:00 - 24:00</h3>
<div className="mt-4 space-y-3">
{programmeringWeek.map((item, index) => (
<motion.article
key={`week-${item.start}-${item.titel}`}
initial={{ opacity: 0, y: 18 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.45, delay: index * 0.07 }}
className="rounded-xl border border-[#d1a24b]/35 bg-[#f7f1e3] px-5 py-4"
>
<p className="text-lg font-semibold text-[#a67a2f]">
{item.start} - {item.eind}
</p>
<p className="text-2xl font-semibold text-[#103a5b]">{item.titel}</p>
</motion.article>
))}
</div>
</div>
<div>
<h3 className="text-2xl font-bold text-[#103a5b]">Weekend (za-zo) 06:00 - 22:00</h3>
<div className="mt-4 space-y-3">
{programmeringWeekend.map((item, index) => (
<motion.article
key={`weekend-${item.start}-${item.titel}`}
initial={{ opacity: 0, y: 18 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.45, delay: index * 0.07 }}
className="rounded-xl border border-[#d1a24b]/35 bg-[#f7f1e3] px-5 py-4"
>
<p className="text-lg font-semibold text-[#a67a2f]">
{item.start} - {item.eind}
</p>
<p className="text-2xl font-semibold text-[#103a5b]">{item.titel}</p>
</motion.article>
))}
</div>
</div>
</div>
</section>
);
}
function ProgrammasPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Programma's</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Klassieke radioformats met de sound, sfeer en opbouw van Hilversum 3 (79-89).
</p>
<div className="mt-10 space-y-5">
{programmas.map((programma, index) => (
<motion.article
key={programma.naam}
initial={{ opacity: 0, x: -18 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ duration: 0.4, delay: index * 0.08 }}
className="border-b border-[#d1a24b]/35 pb-5"
>
<h3 className="text-2xl font-bold text-[#103a5b]">{programma.naam}</h3>
<p className="mt-1 text-[#a67a2f]">{programma.tijd}</p>
<p className="mt-2 text-lg text-[#2b4f69]">{programma.beschrijving}</p>
</motion.article>
))}
</div>
</section>
);
}
function LuisterLivePage() {
return (
<section className="rounded-2xl border border-[#d1a24b]/40 bg-[#103a5b] px-6 py-14 text-center text-[#f5ecd7]">
<h2 className="text-4xl font-bold">Luister Live</h2>
<p className="mx-auto mt-4 max-w-2xl text-lg text-[#e9dbc0]">
De stream staat klaar met een stijl die past bij Meeuwbeemd Radio. Voorbeeldstream: Azzurro Radio.
</p>
<div className="mx-auto mt-10 max-w-2xl rounded-xl bg-[#0b2d45] p-5">
<p className="mb-3 text-sm tracking-wide text-[#d7a84a]">LIVE STREAM</p>
<audio controls className="w-full" src={streamUrl}>
Je browser ondersteunt geen audio player.
</audio>
</div>
<motion.a
href={streamUrl}
target="_blank"
rel="noreferrer"
className="mt-8 inline-block rounded-xl bg-[#d1a24b] px-12 py-4 text-2xl font-bold text-[#103a5b]"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.98 }}
>
Open Stream Direct
</motion.a>
</section>
);
}
function GedraaidPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Laatst gedraaide songs</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Dit zijn de nummers die net op Meeuwbeemd Radio zijn geweest, inclusief cover.
</p>
<div className="mt-10 space-y-3">
{laatstGedraaid.map((song, index) => (
<motion.article
key={`${song.tijd}-${song.titel}`}
initial={{ opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.35, delay: index * 0.06 }}
className="flex items-center gap-4 rounded-xl border border-[#d1a24b]/35 bg-[#f8f2e4] p-3"
>
<img
src={song.cover}
alt={`Cover van ${song.titel}`}
className="h-16 w-16 rounded-lg object-cover"
onError={(event) => {
event.currentTarget.src = fallbackCover;
}}
/>
<div className="min-w-0 flex-1">
<p className="truncate text-xl font-semibold text-[#103a5b]">{song.titel}</p>
<p className="truncate text-[#a67a2f]">{song.artiest}</p>
<p className="truncate text-sm text-[#2b4f69]/85">Album: {song.album}</p>
</div>
<p className="text-lg font-bold text-[#103a5b]">{song.tijd}</p>
</motion.article>
))}
</div>
</section>
);
}
function OverOnsPage() {
return (
<section className="mx-auto max-w-4xl text-center">
<h2 className="text-4xl font-bold text-[#103a5b]">Over Meeuwbeemd Radio</h2>
<p className="mt-6 text-xl leading-relaxed text-[#2b4f69]">
Meeuwbeemd Radio is het huisstation van ons verzorgingshuis. We maken radio met een herkenbare toon, warme
presentatie en muziek die herinneringen oproept.
</p>
<p className="mt-5 text-xl leading-relaxed text-[#2b4f69]">
Onze uitzendingen zorgen voor verbinding tussen bewoners, familie, vrijwilligers en medewerkers. Elke dag
brengen we informatie, verzoeknummers en een vriendelijk geluid op de achtergrond.
</p>
</section>
);
}
function ContactPage() {
return (
<section className="mx-auto max-w-3xl">
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Contact</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Heb je een verzoeknummer of wil je een bericht laten voorlezen? Neem contact met ons op.
</p>
<form className="mt-10 space-y-4 rounded-2xl border border-[#d1a24b]/35 bg-[#f7f1e3] p-6">
<label className="block text-left text-sm font-semibold text-[#103a5b]">
Naam
<input
type="text"
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="Jouw naam"
/>
</label>
<label className="block text-left text-sm font-semibold text-[#103a5b]">
E-mail
<input
type="email"
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="naam@email.nl"
/>
</label>
<label className="block text-left text-sm font-semibold text-[#103a5b]">
Bericht
<textarea
rows={4}
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="Typ hier je verzoek of bericht"
/>
</label>
<button
type="button"
className="rounded-xl bg-[#d1a24b] px-8 py-3 text-lg font-bold text-[#103a5b] transition hover:bg-[#e2b154]"
>
Verstuur
</button>
</form>
</section>
);
}
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
type PageKey =
| "home"
| "programmering"
| "programmas"
| "gedraaid"
| "luister-live"
| "over-ons"
| "contact";
const navigation: Array<{ key: PageKey; label: string }> = [
{ key: "home", label: "Home" },
{ key: "programmering", label: "Programmering" },
{ key: "programmas", label: "Programma's" },
{ key: "gedraaid", label: "Gedraaid" },
{ key: "luister-live", label: "Luister Live" },
{ key: "over-ons", label: "Over Ons" },
{ key: "contact", label: "Contact" },
];
const programmeringWeek = [
{ start: "06:00", eind: "09:00", titel: "Goedemorgen Meeuwbeemd" },
{ start: "09:00", eind: "12:00", titel: "Arbeidsvitaminen 79-89" },
{ start: "12:00", eind: "14:00", titel: "Lunch op 3" },
{ start: "14:00", eind: "16:00", titel: "Middagmix op 3" },
{ start: "16:00", eind: "18:00", titel: "De Avondspits" },
{ start: "18:00", eind: "20:00", titel: "Top 40 Terugblik" },
{ start: "20:00", eind: "22:00", titel: "Vinylavond 80s" },
{ start: "22:00", eind: "24:00", titel: "Nacht op 3" },
];
const programmeringWeekend = [
{ start: "06:00", eind: "09:00", titel: "Weekend Wekker" },
{ start: "09:00", eind: "12:00", titel: "Koffie en Classics" },
{ start: "12:00", eind: "14:00", titel: "Weekendmix" },
{ start: "14:00", eind: "16:00", titel: "Verzoekplaten Parade" },
{ start: "16:00", eind: "18:00", titel: "Nederpop Selectie" },
{ start: "18:00", eind: "20:00", titel: "Gouwe Ouwe Top 80" },
{ start: "20:00", eind: "22:00", titel: "Avondconcert" },
];
const programmas = [
{
naam: "Goedemorgen Meeuwbeemd",
tijd: "Ma t/m vr 06:00 - 09:00",
beschrijving: "Vroege ochtendstart met nieuws, serviceberichten en bekende pop uit 79-89.",
},
{
naam: "Arbeidsvitaminen 79-89",
tijd: "Maandag t/m vrijdag 09:00 - 12:00",
beschrijving: "Non-stop pop en classics uit 1979 tot 1989, precies zoals vroeger op de werkvloer.",
},
{
naam: "Lunch op 3",
tijd: "Ma t/m vr 12:00 - 14:00",
beschrijving: "Luchtige lunchradio met herkenbare jingles, korte items en tijdloze hits.",
},
{
naam: "Middagmix op 3",
tijd: "Dagelijks 14:00 - 16:00",
beschrijving: "De beste mix van Nederlandse en internationale radiohits uit de jaren 80.",
},
{
naam: "De Avondspits",
tijd: "Dagelijks 16:00 - 18:00",
beschrijving: "Tempo, verkeer en meezingers voor het einde van de middag.",
},
{
naam: "Top 40 Terugblik",
tijd: "Dagelijks 18:00 - 20:00",
beschrijving: "De grootste hits uit de Nederlandse Top 40 van de jaren 80, met radiofragmenten en intro's.",
},
{
naam: "Vinylavond 80s",
tijd: "Dagelijks 20:00 - 22:00",
beschrijving: "Een warme avondplaat met new wave, synthpop en soft rock van 1979 tot 1989.",
},
{
naam: "Nacht op 3",
tijd: "Ma t/m vr 22:00 - 24:00",
beschrijving: "Rustige nachturen met late-night classics en vertrouwde stemvoering in retro radio-stijl.",
},
{
naam: "Weekend Wekker",
tijd: "Za en zo 06:00 - 09:00",
beschrijving: "Ontspannen weekendstart met warme oldies en vriendelijke presentatie.",
},
{
naam: "Koffie en Classics",
tijd: "Za en zo 09:00 - 12:00",
beschrijving: "Drie uur lang rustige classics, luisteraarsgroeten en vertrouwde sfeer.",
},
{
naam: "Verzoekplaten Parade",
tijd: "Za en zo 14:00 - 16:00",
beschrijving: "Populaire verzoekplaten van bewoners en familie, met korte introducties.",
},
];
const laatstGedraaid = [
{
tijd: "14:52",
titel: "Ti Amo",
artiest: "Umberto Tozzi",
album: "Ti Amo",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/6/6e/Umberto_Tozzi_Ti_Amo.jpg/320px-Umberto_Tozzi_Ti_Amo.jpg",
},
{
tijd: "14:48",
titel: "Volare (Nel Blu Dipinto Di Blu)",
artiest: "Domenico Modugno",
album: "Nel Blu Dipinto Di Blu",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/d/d4/Nel_Blu_Dipinto_Di_Blu_cover.jpg/320px-Nel_Blu_Dipinto_Di_Blu_cover.jpg",
},
{
tijd: "14:44",
titel: "Gloria",
artiest: "Umberto Tozzi",
album: "Gloria",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/0/0f/Umberto_Tozzi_Gloria.jpg/320px-Umberto_Tozzi_Gloria.jpg",
},
{
tijd: "14:39",
titel: "Sarà perché ti amo",
artiest: "Ricchi e Poveri",
album: "E penso a te",
cover:
"https://upload.wikimedia.org/wikipedia/en/thumb/e/e6/Sara_perche_ti_amo.jpg/320px-Sara_perche_ti_amo.jpg",
},
{
tijd: "14:35",
titel: "Felicità",
artiest: "Al Bano & Romina Power",
album: "Felicità",
cover: "https://upload.wikimedia.org/wikipedia/en/thumb/1/15/Felicita_cover.jpg/320px-Felicita_cover.jpg",
},
];
const fallbackCover =
"https://images.unsplash.com/photo-1511379938547-c1f69419868d?auto=format&fit=crop&w=300&q=80";
const streamUrl = "https://reteradioazzurra.radioca.st/stream";
const logoUrl = "/images/meeuwbeemd-logo.png";
function getHashPage(): PageKey {
const hash = window.location.hash.replace("#", "") as PageKey;
return navigation.some((item) => item.key === hash) ? hash : "home";
}
export default function App() {
const [activePage, setActivePage] = useState<PageKey>(getHashPage());
useEffect(() => {
const onHashChange = () => setActivePage(getHashPage());
window.addEventListener("hashchange", onHashChange);
return () => window.removeEventListener("hashchange", onHashChange);
}, []);
return (
<div className="min-h-screen bg-[#f2ebd8] text-[#103a5b]">
<header className="sticky top-0 z-20 border-b border-[#d1a24b]/40 bg-[#103a5b]/95 backdrop-blur">
<div className="mx-auto flex max-w-6xl flex-wrap items-center justify-between gap-4 px-6 py-3">
<a href="#home" className="flex items-center gap-3">
<img src={logoUrl} alt="Meeuwbeemd Radio logo" className="h-12 w-12 rounded-full border border-[#d1a24b]/60" />
<span className="text-lg font-extrabold tracking-wide text-[#f5ecd7] sm:text-2xl">MEEUWBEEMD RADIO</span>
</a>
<nav className="flex flex-wrap gap-4 text-sm font-semibold text-[#f5ecd7]">
{navigation.map((item) => (
<a
key={item.key}
href={`#${item.key}`}
className={`transition-colors hover:text-[#d7a84a] ${activePage === item.key ? "text-[#d7a84a] underline underline-offset-4" : ""}`}
>
{item.label}
</a>
))}
</nav>
</div>
</header>
<main className="mx-auto max-w-6xl px-6 py-12">
{activePage === "home" && <HomePage />}
{activePage === "programmering" && <ProgrammeringPage />}
{activePage === "programmas" && <ProgrammasPage />}
{activePage === "gedraaid" && <GedraaidPage />}
{activePage === "luister-live" && <LuisterLivePage />}
{activePage === "over-ons" && <OverOnsPage />}
{activePage === "contact" && <ContactPage />}
</main>
<footer className="bg-[#103a5b] px-6 py-10 text-center text-[#f5ecd7]">
<img src={logoUrl} alt="Meeuwbeemd Radio logo" className="mx-auto h-20 w-20 rounded-full border-2 border-[#d1a24b]/80" />
<p className="mt-4 text-xl font-semibold text-[#f5ecd7]">Meeuwbeemd Radio - Muziek en informatie voor elke dag</p>
<p className="mt-2 text-base text-[#e7d8b7]">Copyright Verzorgingshuis Meeuwbeemd</p>
</footer>
</div>
);
}
function HomePage() {
return (
<section className="relative overflow-hidden rounded-2xl border border-[#d1a24b]/30 bg-gradient-to-b from-[#153f61] via-[#103a5b] to-[#0d314d]">
<motion.div
className="absolute inset-0"
animate={{ backgroundPositionX: ["0%", "100%", "0%"] }}
transition={{ duration: 26, repeat: Infinity, ease: "easeInOut" }}
style={{
backgroundImage:
"radial-gradient(circle at 10% 20%, rgba(209,162,75,0.18) 0 8%, transparent 9%), radial-gradient(circle at 70% 25%, rgba(209,162,75,0.13) 0 11%, transparent 12%), radial-gradient(circle at 30% 80%, rgba(245,236,215,0.1) 0 9%, transparent 10%)",
backgroundSize: "760px 360px",
}}
/>
<div className="relative mx-auto flex min-h-[72vh] max-w-4xl flex-col items-center justify-center gap-8 px-6 py-14 text-center">
<motion.img
src={logoUrl}
alt="Meeuwbeemd Radio"
className="h-44 w-44 rounded-full border-4 border-[#d1a24b]/70 shadow-[0_18px_40px_rgba(0,0,0,0.28)] md:h-56 md:w-56"
initial={{ opacity: 0, scale: 0.85, y: 16 }}
animate={{ opacity: 1, scale: 1, y: [0, -5, 0] }}
transition={{ duration: 0.9, y: { duration: 4.5, repeat: Infinity, ease: "easeInOut" } }}
/>
<motion.p
initial={{ opacity: 0, y: 18 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="text-base font-semibold tracking-[0.2em] text-[#d7a84a]"
>
MEEUWBEEMD RADIO
</motion.p>
<motion.h1
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.1 }}
className="text-4xl leading-tight font-extrabold text-[#f5ecd7] md:text-6xl"
>
Muziek en informatie voor elke dag
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.2 }}
className="max-w-2xl text-lg text-[#e9dbc0]"
>
Het vertrouwde geluid voor bewoners en bezoekers. Rust, herkenning en gezelligheid in elk uur van de dag.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.75, delay: 0.3 }}
className="flex flex-wrap items-center justify-center gap-4"
>
<a
href="#luister-live"
className="rounded-xl bg-[#d1a24b] px-10 py-4 text-xl font-bold text-[#103a5b] shadow-[0_8px_25px_rgba(0,0,0,0.28)] transition hover:scale-[1.03] hover:bg-[#e2b154]"
>
Luister Live
</a>
<a
href="#programmering"
className="rounded-xl border-2 border-[#d1a24b] bg-transparent px-8 py-4 text-xl font-bold text-[#f5ecd7] transition hover:bg-[#d1a24b]/10"
>
Bekijk Programmering
</a>
</motion.div>
</div>
</section>
);
}
function ProgrammeringPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Vandaag op de radio</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Programmering in Hilversum 3 stijl uit de jaren 1979 tot 1989.
</p>
<div className="mt-10 grid gap-8 lg:grid-cols-2">
<div>
<h3 className="text-2xl font-bold text-[#103a5b]">Doordeweeks (ma-vr) 06:00 - 24:00</h3>
<div className="mt-4 space-y-3">
{programmeringWeek.map((item, index) => (
<motion.article
key={`week-${item.start}-${item.titel}`}
initial={{ opacity: 0, y: 18 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.45, delay: index * 0.07 }}
className="rounded-xl border border-[#d1a24b]/35 bg-[#f7f1e3] px-5 py-4"
>
<p className="text-lg font-semibold text-[#a67a2f]">
{item.start} - {item.eind}
</p>
<p className="text-2xl font-semibold text-[#103a5b]">{item.titel}</p>
</motion.article>
))}
</div>
</div>
<div>
<h3 className="text-2xl font-bold text-[#103a5b]">Weekend (za-zo) 06:00 - 22:00</h3>
<div className="mt-4 space-y-3">
{programmeringWeekend.map((item, index) => (
<motion.article
key={`weekend-${item.start}-${item.titel}`}
initial={{ opacity: 0, y: 18 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.45, delay: index * 0.07 }}
className="rounded-xl border border-[#d1a24b]/35 bg-[#f7f1e3] px-5 py-4"
>
<p className="text-lg font-semibold text-[#a67a2f]">
{item.start} - {item.eind}
</p>
<p className="text-2xl font-semibold text-[#103a5b]">{item.titel}</p>
</motion.article>
))}
</div>
</div>
</div>
</section>
);
}
function ProgrammasPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Programma's</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Klassieke radioformats met de sound, sfeer en opbouw van Hilversum 3 (79-89).
</p>
<div className="mt-10 space-y-5">
{programmas.map((programma, index) => (
<motion.article
key={programma.naam}
initial={{ opacity: 0, x: -18 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ duration: 0.4, delay: index * 0.08 }}
className="border-b border-[#d1a24b]/35 pb-5"
>
<h3 className="text-2xl font-bold text-[#103a5b]">{programma.naam}</h3>
<p className="mt-1 text-[#a67a2f]">{programma.tijd}</p>
<p className="mt-2 text-lg text-[#2b4f69]">{programma.beschrijving}</p>
</motion.article>
))}
</div>
</section>
);
}
function LuisterLivePage() {
return (
<section className="rounded-2xl border border-[#d1a24b]/40 bg-[#103a5b] px-6 py-14 text-center text-[#f5ecd7]">
<h2 className="text-4xl font-bold">Luister Live</h2>
<p className="mx-auto mt-4 max-w-2xl text-lg text-[#e9dbc0]">
De stream staat klaar met een stijl die past bij Meeuwbeemd Radio. Voorbeeldstream: Azzurro Radio.
</p>
<div className="mx-auto mt-10 max-w-2xl rounded-xl bg-[#0b2d45] p-5">
<p className="mb-3 text-sm tracking-wide text-[#d7a84a]">LIVE STREAM</p>
<audio controls className="w-full" src={streamUrl}>
Je browser ondersteunt geen audio player.
</audio>
</div>
<motion.a
href={streamUrl}
target="_blank"
rel="noreferrer"
className="mt-8 inline-block rounded-xl bg-[#d1a24b] px-12 py-4 text-2xl font-bold text-[#103a5b]"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.98 }}
>
Open Stream Direct
</motion.a>
</section>
);
}
function GedraaidPage() {
return (
<section>
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Laatst gedraaide songs</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Dit zijn de nummers die net op Meeuwbeemd Radio zijn geweest, inclusief cover.
</p>
<div className="mt-10 space-y-3">
{laatstGedraaid.map((song, index) => (
<motion.article
key={`${song.tijd}-${song.titel}`}
initial={{ opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.4 }}
transition={{ duration: 0.35, delay: index * 0.06 }}
className="flex items-center gap-4 rounded-xl border border-[#d1a24b]/35 bg-[#f8f2e4] p-3"
>
<img
src={song.cover}
alt={`Cover van ${song.titel}`}
className="h-16 w-16 rounded-lg object-cover"
onError={(event) => {
event.currentTarget.src = fallbackCover;
}}
/>
<div className="min-w-0 flex-1">
<p className="truncate text-xl font-semibold text-[#103a5b]">{song.titel}</p>
<p className="truncate text-[#a67a2f]">{song.artiest}</p>
<p className="truncate text-sm text-[#2b4f69]/85">Album: {song.album}</p>
</div>
<p className="text-lg font-bold text-[#103a5b]">{song.tijd}</p>
</motion.article>
))}
</div>
</section>
);
}
function OverOnsPage() {
return (
<section className="mx-auto max-w-4xl text-center">
<h2 className="text-4xl font-bold text-[#103a5b]">Over Meeuwbeemd Radio</h2>
<p className="mt-6 text-xl leading-relaxed text-[#2b4f69]">
Meeuwbeemd Radio is het huisstation van ons verzorgingshuis. We maken radio met een herkenbare toon, warme
presentatie en muziek die herinneringen oproept.
</p>
<p className="mt-5 text-xl leading-relaxed text-[#2b4f69]">
Onze uitzendingen zorgen voor verbinding tussen bewoners, familie, vrijwilligers en medewerkers. Elke dag
brengen we informatie, verzoeknummers en een vriendelijk geluid op de achtergrond.
</p>
</section>
);
}
function ContactPage() {
return (
<section className="mx-auto max-w-3xl">
<h2 className="text-center text-4xl font-bold text-[#103a5b]">Contact</h2>
<p className="mx-auto mt-4 max-w-2xl text-center text-lg text-[#2b4f69]">
Heb je een verzoeknummer of wil je een bericht laten voorlezen? Neem contact met ons op.
</p>
<form className="mt-10 space-y-4 rounded-2xl border border-[#d1a24b]/35 bg-[#f7f1e3] p-6">
<label className="block text-left text-sm font-semibold text-[#103a5b]">
Naam
<input
type="text"
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="Jouw naam"
/>
</label>
<label className="block text-left text-sm font-semibold text-[#103a5b]">
E-mail
<input
type="email"
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="naam@email.nl"
/>
</label>
<label className="block text-left text-sm font-semibold text-[#103a5b]">
Bericht
<textarea
rows={4}
className="mt-1 w-full rounded-lg border border-[#d1a24b]/40 bg-white px-4 py-3 text-[#103a5b] outline-none focus:border-[#a67a2f]"
placeholder="Typ hier je verzoek of bericht"
/>
</label>
<button
type="button"
className="rounded-xl bg-[#d1a24b] px-8 py-3 text-lg font-bold text-[#103a5b] transition hover:bg-[#e2b154]"
>
Verstuur
</button>
</form>
</section>
);
}