Blog

  • Hello world!

    import React, { useMemo, useState } from “react”;
    import { motion } from “framer-motion”;
    import { Plus, Trash2, RotateCcw, Ruler, Euro, Download, Home } from “lucide-react”;
    import { Button } from “@/components/ui/button”;
    import { Card, CardContent } from “@/components/ui/card”;

    const MODULES = [
    { id: “base60”, name: “Onderkast 60”, width: 60, depth: 60, price: 240, type: “Onderkast” },
    { id: “base80”, name: “Onderkast 80”, width: 80, depth: 60, price: 310, type: “Onderkast” },
    { id: “sink80”, name: “Spoelkast 80”, width: 80, depth: 60, price: 390, type: “Spoelzone” },
    { id: “hob60”, name: “Kookplaatkast 60”, width: 60, depth: 60, price: 430, type: “Kookzone” },
    { id: “drawer90”, name: “Ladekast 90”, width: 90, depth: 60, price: 520, type: “Opbergen” },
    { id: “tall60”, name: “Hoge kast 60”, width: 60, depth: 60, price: 690, type: “Hoge kast” },
    { id: “fridge60”, name: “Koelkastkast 60”, width: 60, depth: 60, price: 850, type: “Apparatuur” },
    { id: “oven60”, name: “Ovenkast 60”, width: 60, depth: 60, price: 760, type: “Apparatuur” },
    ];

    const LAYOUTS = [
    { id: “straight”, label: “Rechte keuken”, description: “Alle modules langs één wand.” },
    { id: “lshape”, label: “L-keuken”, description: “Modules verdeeld over twee wanden.” },
    { id: “island”, label: “Keuken met eiland”, description: “Wandopstelling plus los eiland.” },
    ];

    function currency(value) {
    return new Intl.NumberFormat(“nl-NL”, { style: “currency”, currency: “EUR”, maximumFractionDigits: 0 }).format(value);
    }

    function fitStatus(totalWidth, roomWidth) {
    if (totalWidth <= roomWidth) return { label: "Past", tone: "bg-emerald-100 text-emerald-800" }; return { label: "Te breed", tone: "bg-red-100 text-red-800" }; } export default function KitchenDesigner() { const [roomWidth, setRoomWidth] = useState(360); const [roomDepth, setRoomDepth] = useState(260); const [layout, setLayout] = useState("straight"); const [selectedType, setSelectedType] = useState("Alles"); const [items, setItems] = useState([ { uid: crypto.randomUUID(), ...MODULES[1], zone: "wand" }, { uid: crypto.randomUUID(), ...MODULES[2], zone: "wand" }, { uid: crypto.randomUUID(), ...MODULES[3], zone: "wand" }, ]); const filteredModules = useMemo(() => {
    if (selectedType === “Alles”) return MODULES;
    return MODULES.filter((m) => m.type === selectedType);
    }, [selectedType]);

    const totalWidth = items.filter((i) => i.zone === “wand”).reduce((sum, i) => sum + i.width, 0);
    const islandWidth = items.filter((i) => i.zone === “eiland”).reduce((sum, i) => sum + i.width, 0);
    const cabinetsPrice = items.reduce((sum, i) => sum + i.price, 0);
    const worktopPrice = Math.ceil((totalWidth + islandWidth) / 100) * 180;
    const installPrice = Math.max(850, Math.ceil(items.length * 115));
    const totalPrice = cabinetsPrice + worktopPrice + installPrice;
    const status = fitStatus(totalWidth, roomWidth);

    const addModule = (module) => {
    const zone = layout === “island” && [“drawer90”, “base80”, “base60”].includes(module.id) && islandWidth < 180 ? "eiland" : "wand"; setItems((prev) => […prev, { uid: crypto.randomUUID(), …module, zone }]);
    };

    const removeModule = (uid) => setItems((prev) => prev.filter((item) => item.uid !== uid));

    const reset = () => {
    setLayout(“straight”);
    setRoomWidth(360);
    setRoomDepth(260);
    setItems([
    { uid: crypto.randomUUID(), …MODULES[1], zone: “wand” },
    { uid: crypto.randomUUID(), …MODULES[2], zone: “wand” },
    { uid: crypto.randomUUID(), …MODULES[3], zone: “wand” },
    ]);
    };

    const exportDesign = () => {
    const data = {
    ruimte: { breedte_cm: roomWidth, diepte_cm: roomDepth },
    layout,
    modules: items.map(({ uid, name, width, depth, price, zone }) => ({ uid, name, width, depth, price, zone })),
    prijsindicatie: { kasten: cabinetsPrice, werkblad: worktopPrice, montage: installPrice, totaal: totalPrice },
    };
    const blob = new Blob([JSON.stringify(data, null, 2)], { type: “application/json” });
    const url = URL.createObjectURL(blob);
    const a = document.createElement(“a”);
    a.href = url;
    a.download = “keukenontwerp.json”;
    a.click();
    URL.revokeObjectURL(url);
    };

    const scale = 1.35;
    const roomSvgWidth = Math.max(420, roomWidth * scale);
    const roomSvgHeight = Math.max(260, roomDepth * scale);

    return (

    Online configurator

    Keukenontwerp systeem

    Stel een keuken samen, controleer of de indeling past en exporteer het ontwerp als JSON.


    } label=”Wandbreedte” value={`${totalWidth} cm`} badge={status} />
    } label=”Eiland” value={`${islandWidth} cm`} />
    } label=”Prijsindicatie” value={currency(totalPrice)} />
    } label=”Modules” value={items.length} />


    Live plattegrond

    Schaal is indicatief. Grijze vlakken zijn keukenmodules.

    {status.label}

    {roomWidth} × {roomDepth} cm {items.filter((i) => i.zone === “wand”).map((item, index) => { const x = 14 + items.filter((i) => i.zone === “wand”).slice(0, index).reduce((sum, i) => sum + i.width, 0) * scale; return ; })} {layout === “lshape” && items.slice(0, Math.min(3, items.length)).map((item, index) => ( ))} {layout === “island” && items.filter((i) => i.zone === “eiland”).map((item, index) => { const x = roomWidth * scale / 2 – islandWidth * scale / 2 + items.filter((i) => i.zone === “eiland”).slice(0, index).reduce((sum, i) => sum + i.width, 0) * scale; const y = Math.min(roomDepth * scale – 95, 190); return ; })}



    Geselecteerde modules

    {items.map((item) => (

    {item.name}
    {item.zone} · {item.width} cm · {currency(item.price)}

    ))}



    Prijsopbouw



    Deze prijs is een indicatie. Koppel dit systeem aan je eigen productdatabase voor actuele voorraad, materialen en marges.


    );
    }

    function Metric({ icon, label, value, badge }) {
    return (

    {icon}

    {badge && {badge.label}}

    {label}
    {value}



    );
    }

    function KitchenBlock({ x, y, w, h, label }) {
    return (

    {label}

    );
    }

    function PriceRow({ label, value, strong = false }) {
    return (

    {label}
    {currency(value)}

    );
    }