Add premium configurator with split-screen layout

- Redesigned configurator page with split-screen interface
- Left: Large visual preview with sticky positioning
- Right: Premium white controls container with form steps
- Added complete configurator wizard (5 steps)
- Updated hero CTA to "Zelf ontwerpen"
- Configured Shadcn UI with Slate theme
- Added layout components (Navbar, Footer)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Ubuntu
2026-02-10 15:59:37 +00:00
parent c283d7193a
commit 9cf5cea3ba
55 changed files with 8411 additions and 99 deletions

View File

@@ -0,0 +1,186 @@
import Link from "next/link";
import { Mail, Phone, Star, Facebook, Instagram, Linkedin, Youtube } from "lucide-react";
const contactInfo = [
{ icon: Mail, text: "info@proinn.nl", href: "mailto:info@proinn.nl" },
{ icon: Phone, text: "085 - 1234 567", href: "tel:0851234567" },
];
const companyInfo = [
{ label: "KVK", value: "12345678" },
{ label: "BTW", value: "NL123456789B01" },
{ label: "IBAN", value: "NL00 INGB 0000 0000 00" },
];
const locations = [
"Nunspeet",
"Veghel",
"Amsterdam",
"Rotterdam",
"Utrecht",
];
const proinnLinks = [
{ label: "Projecten", href: "/projecten" },
{ label: "Configurator", href: "/offerte" },
{ label: "Over ons", href: "/over-ons" },
{ label: "Vacatures", href: "/vacatures" },
{ label: "Showrooms", href: "/showrooms" },
];
const serviceLinks = [
{ label: "Contact", href: "/contact" },
{ label: "Kennisbank", href: "/kennisbank" },
{ label: "Veelgestelde vragen", href: "/faq" },
{ label: "Garantie", href: "/garantie" },
{ label: "Onderhoud", href: "/onderhoud" },
];
const socialLinks = [
{ icon: Facebook, href: "#", label: "Facebook" },
{ icon: Instagram, href: "#", label: "Instagram" },
{ icon: Linkedin, href: "#", label: "LinkedIn" },
{ icon: Youtube, href: "#", label: "YouTube" },
];
export function Footer() {
return (
<footer className="bg-[#1A2E2E]">
{/* Main Footer */}
<div className="mx-auto max-w-7xl px-4 pt-16 pb-12 sm:px-6 lg:px-8">
<div className="grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-5 lg:gap-8">
{/* Col 1 - Logo & Contact */}
<div className="lg:col-span-1">
<Link href="/" className="text-2xl font-extrabold tracking-tight text-white">
PROINN
</Link>
<div className="mt-6 space-y-3">
{contactInfo.map((item) => (
<a
key={item.text}
href={item.href}
className="flex items-center gap-2 text-sm text-gray-400 transition-colors hover:text-white"
>
<item.icon className="size-4 shrink-0" />
{item.text}
</a>
))}
</div>
<div className="mt-5 space-y-2">
{companyInfo.map((item) => (
<p key={item.label} className="text-xs text-gray-500">
<span className="text-gray-400">{item.label}:</span> {item.value}
</p>
))}
</div>
</div>
{/* Col 2 - Locaties */}
<div>
<h4 className="mb-4 text-sm font-semibold text-white">Locaties</h4>
<ul className="space-y-2.5">
{locations.map((city) => (
<li key={city}>
<Link
href={`/showrooms/${city.toLowerCase()}`}
className="text-sm text-gray-400 transition-colors hover:text-white"
>
{city}
</Link>
</li>
))}
</ul>
</div>
{/* Col 3 - Proinn */}
<div>
<h4 className="mb-4 text-sm font-semibold text-white">Proinn</h4>
<ul className="space-y-2.5">
{proinnLinks.map((link) => (
<li key={link.label}>
<Link
href={link.href}
className="text-sm text-gray-400 transition-colors hover:text-white"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
{/* Col 4 - Service */}
<div>
<h4 className="mb-4 text-sm font-semibold text-white">Service</h4>
<ul className="space-y-2.5">
{serviceLinks.map((link) => (
<li key={link.label}>
<Link
href={link.href}
className="text-sm text-gray-400 transition-colors hover:text-white"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
{/* Col 5 - Trustpilot */}
<div>
<div className="rounded-2xl bg-[#243636] p-6">
<p className="mb-3 text-xs font-medium uppercase tracking-wider text-gray-400">
Klantwaardering
</p>
<div className="mb-2 flex items-center gap-1">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className="size-5 fill-yellow-400 text-yellow-400"
/>
))}
</div>
<p className="text-2xl font-bold text-white">
4.8<span className="text-sm font-normal text-gray-400">/5</span>
</p>
<div className="mt-2 flex items-center gap-1.5">
<Star className="size-4 fill-green-500 text-green-500" />
<span className="text-sm text-gray-400">Trustpilot</span>
</div>
</div>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-white/10">
<div className="mx-auto flex max-w-7xl flex-col items-center justify-between gap-4 px-4 py-6 sm:flex-row sm:px-6 lg:px-8">
{/* Social Icons */}
<div className="flex items-center gap-4">
{socialLinks.map((social) => (
<a
key={social.label}
href={social.href}
aria-label={social.label}
className="flex size-9 items-center justify-center rounded-full bg-white/10 text-gray-400 transition-colors hover:bg-white/20 hover:text-white"
>
<social.icon className="size-4" />
</a>
))}
</div>
{/* Legal Links */}
<div className="flex items-center gap-6 text-xs text-gray-500">
<span>&copy; {new Date().getFullYear()} Proinn</span>
<Link href="/privacy" className="transition-colors hover:text-gray-300">
Privacybeleid
</Link>
<Link href="/voorwaarden" className="transition-colors hover:text-gray-300">
Algemene voorwaarden
</Link>
</div>
</div>
</div>
</footer>
);
}

View File

@@ -0,0 +1,11 @@
import { TopBar } from "./top-bar";
import { MainNav } from "./main-nav";
export function Header() {
return (
<header className="sticky top-0 z-50 w-full shadow-sm">
<TopBar />
<MainNav />
</header>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import Link from "next/link";
import { Menu } from "lucide-react";
import { MobileMenu } from "./mobile-menu";
import { useState } from "react";
export function MainNav() {
const [menuOpen, setMenuOpen] = useState(false);
return (
<>
<div className="bg-white">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Logo */}
<Link
href="/"
className="text-2xl font-extrabold tracking-tight text-gray-900"
>
PROINN
</Link>
{/* Right side: CTA + Hamburger */}
<div className="flex items-center gap-3">
<Link
href="/offerte"
className="inline-flex items-center rounded-md bg-[#C4D668] px-5 py-2.5 text-sm font-semibold text-black transition-colors hover:bg-[#b5c75a]"
>
Vraag Offerte
</Link>
<button
onClick={() => setMenuOpen(true)}
className="inline-flex size-11 items-center justify-center rounded-md bg-gray-100 text-gray-600 transition-colors hover:bg-gray-200"
aria-label="Menu openen"
>
<Menu className="size-5" />
</button>
</div>
</div>
</div>
<MobileMenu open={menuOpen} onOpenChange={setMenuOpen} />
</>
);
}

View File

@@ -0,0 +1,91 @@
"use client";
import Link from "next/link";
import { ChevronDown, Phone, Mail } from "lucide-react";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet";
const menuLinks = [
{ href: "/", label: "Home" },
{ href: "/producten", label: "Producten", hasSubmenu: true },
{ href: "/maatwerk", label: "Maatwerk", hasSubmenu: true },
{ href: "/over-ons", label: "Over Ons" },
{ href: "/contact", label: "Contact" },
];
interface MobileMenuProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function MobileMenu({ open, onOpenChange }: MobileMenuProps) {
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent side="right" className="flex w-full max-w-sm flex-col p-0">
<SheetHeader className="border-b px-6 py-4">
<SheetTitle className="text-left text-lg font-extrabold tracking-tight">
PROINN
</SheetTitle>
</SheetHeader>
{/* Navigation Links */}
<nav className="flex-1 overflow-y-auto px-6 py-4">
<ul className="space-y-1">
{menuLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
onClick={() => onOpenChange(false)}
className="flex items-center justify-between rounded-md px-3 py-3 text-base font-medium text-gray-800 transition-colors hover:bg-gray-50"
>
{link.label}
{link.hasSubmenu && (
<ChevronDown className="size-4 text-gray-400" />
)}
</Link>
</li>
))}
</ul>
{/* CTA Button */}
<div className="mt-6">
<Link
href="/offerte"
onClick={() => onOpenChange(false)}
className="flex w-full items-center justify-center rounded-md bg-[#C4D668] px-5 py-3 text-sm font-semibold text-black transition-colors hover:bg-[#b5c75a]"
>
Vraag Offerte
</Link>
</div>
</nav>
{/* Footer Block */}
<div className="bg-[#2F3B3B] px-6 py-6">
<p className="mb-3 text-sm font-semibold text-white">
Wil je wat vragen?
</p>
<div className="space-y-2">
<a
href="tel:0851234567"
className="flex items-center gap-2 text-sm text-gray-300 transition-colors hover:text-white"
>
<Phone className="size-4" />
085 - 1234 567
</a>
<a
href="mailto:info@proinn.nl"
className="flex items-center gap-2 text-sm text-gray-300 transition-colors hover:text-white"
>
<Mail className="size-4" />
info@proinn.nl
</a>
</div>
</div>
</SheetContent>
</Sheet>
);
}

View File

@@ -0,0 +1,81 @@
"use client";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { Menu, X } from "lucide-react";
import { useState } from "react";
import { cn } from "@/lib/utils";
const navLinks = [
{ href: "/", label: "Home" },
{ href: "/producten", label: "Producten" },
{ href: "/maatwerk", label: "Maatwerk" },
{ href: "/contact", label: "Contact" },
];
export function Navbar() {
const [mobileOpen, setMobileOpen] = useState(false);
return (
<nav className="fixed top-0 left-0 right-0 z-50 border-b border-border/40 bg-background/80 backdrop-blur-lg">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Logo */}
<Link href="/" className="text-xl font-bold tracking-tighter text-foreground">
PROINN
</Link>
{/* Desktop Navigation */}
<div className="hidden items-center gap-1 md:flex">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className="rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
>
{link.label}
</Link>
))}
</div>
{/* CTA Button + Mobile Toggle */}
<div className="flex items-center gap-3">
<Button
asChild
size="sm"
className="bg-brand-orange text-white hover:bg-brand-orange/90"
>
<Link href="/offerte">Vraag Offerte</Link>
</Button>
<button
onClick={() => setMobileOpen(!mobileOpen)}
className="inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:text-foreground md:hidden"
>
{mobileOpen ? <X className="size-5" /> : <Menu className="size-5" />}
</button>
</div>
</div>
{/* Mobile Navigation */}
<div
className={cn(
"overflow-hidden border-t border-border/40 bg-background/95 backdrop-blur-lg transition-all duration-200 md:hidden",
mobileOpen ? "max-h-64" : "max-h-0 border-t-0"
)}
>
<div className="space-y-1 px-4 py-3">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
onClick={() => setMobileOpen(false)}
className="block rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
>
{link.label}
</Link>
))}
</div>
</div>
</nav>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import { Star, Phone, Globe } from "lucide-react";
export function TopBar() {
return (
<div className="bg-[#E8E8E6]">
<div className="mx-auto flex h-10 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Trustpilot */}
<div className="flex items-center gap-1.5">
<div className="flex items-center gap-0.5">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className="size-3.5 fill-yellow-400 text-yellow-400"
/>
))}
</div>
<span className="text-xs font-bold text-gray-700">4.8/5</span>
<div className="flex items-center gap-1">
<Star className="size-3.5 fill-green-600 text-green-600" />
<span className="text-xs font-medium text-gray-600">
Trustpilot
</span>
</div>
</div>
{/* Contact & Language */}
<div className="flex items-center gap-4 text-xs text-gray-600">
<a
href="tel:0851234567"
className="flex items-center gap-1.5 font-medium transition-colors hover:text-gray-900"
>
<Phone className="size-3.5" />
<span>085 - 1234 567</span>
</a>
<div className="h-3.5 w-px bg-gray-400" />
<div className="flex items-center gap-1.5 font-medium">
<Globe className="size-3.5" />
<span>NL</span>
</div>
</div>
</div>
</div>
);
}