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)}

);
}

Reacties

Één reactie op “Hello world!”

  1. A WordPress Commenter avatar

    Hi, this is a comment.
    To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard.
    Commenter avatars come from Gravatar.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Meer berichten