Files
ben.de-roo.org/domme-converters/index.hml
T
2026-06-24 20:43:39 +02:00

646 lines
21 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Converterland™ — Onzin-adapters voor élke situatie</title>
<style>
:root {
--bg: #0f1115;
--surface: #1a1d24;
--surface-2: #232730;
--border: #2e333d;
--text: #e7e9ee;
--muted: #9aa1ad;
--brand: #ff7a3d;
--brand-dark: #e2632a;
--accent: #36d399;
--radius: 14px;
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: var(--font);
background: var(--bg);
color: var(--text);
line-height: 1.5;
}
a { color: inherit; }
/* ---------- Header ---------- */
header {
position: sticky;
top: 0;
z-index: 40;
background: rgba(15, 17, 21, 0.85);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border);
}
.nav {
max-width: 1120px;
margin: 0 auto;
padding: 14px 20px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.logo {
display: flex;
align-items: center;
gap: 10px;
font-weight: 800;
font-size: 20px;
letter-spacing: -0.5px;
}
.logo .mark {
width: 34px; height: 34px;
border-radius: 9px;
background: var(--brand);
display: grid;
place-items: center;
font-size: 18px;
color: #1a1208;
transform: rotate(-8deg);
}
.logo small {
display: block;
font-size: 11px;
font-weight: 500;
color: var(--muted);
letter-spacing: 0.5px;
}
.cart-btn {
position: relative;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
padding: 10px 16px;
border-radius: 999px;
font-weight: 600;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: background .15s, border-color .15s;
}
.cart-btn:hover { background: var(--surface-2); border-color: var(--brand); }
.cart-count {
background: var(--brand);
color: #1a1208;
font-size: 12px;
font-weight: 800;
min-width: 20px;
height: 20px;
padding: 0 6px;
border-radius: 999px;
display: grid;
place-items: center;
}
/* ---------- Hero ---------- */
.hero {
max-width: 1120px;
margin: 0 auto;
padding: 56px 20px 30px;
text-align: center;
}
.hero .badge {
display: inline-block;
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--accent);
padding: 6px 14px;
border-radius: 999px;
font-size: 13px;
font-weight: 600;
margin-bottom: 20px;
}
.hero h1 {
font-size: clamp(32px, 6vw, 56px);
line-height: 1.05;
margin: 0 0 16px;
letter-spacing: -1.5px;
}
.hero h1 .hl { color: var(--brand); }
.hero p {
color: var(--muted);
font-size: 18px;
max-width: 620px;
margin: 0 auto;
}
.disclaimer {
margin: 22px auto 0;
max-width: 560px;
font-size: 13px;
color: var(--muted);
background: var(--surface);
border: 1px dashed var(--border);
padding: 10px 16px;
border-radius: var(--radius);
}
/* ---------- Products ---------- */
.section-title {
max-width: 1120px;
margin: 30px auto 0;
padding: 0 20px;
display: flex;
align-items: baseline;
justify-content: space-between;
}
.section-title h2 { font-size: 24px; margin: 0; letter-spacing: -0.5px; }
.section-title span { color: var(--muted); font-size: 14px; }
.grid {
max-width: 1120px;
margin: 20px auto 60px;
padding: 0 20px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 18px;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
display: flex;
flex-direction: column;
transition: transform .15s, border-color .15s;
}
.card:hover { transform: translateY(-4px); border-color: var(--brand); }
.card .thumb {
height: 140px;
display: grid;
place-items: center;
font-size: 54px;
background: radial-gradient(circle at 50% 30%, var(--surface-2), var(--surface));
border-bottom: 1px solid var(--border);
}
.card .body { padding: 16px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.card h3 { margin: 0; font-size: 16px; letter-spacing: -0.3px; }
.card .desc { color: var(--muted); font-size: 13px; flex: 1; }
.card .rating { font-size: 12px; color: var(--accent); }
.card .foot {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 6px;
}
.price { font-weight: 800; font-size: 18px; }
.price small { color: var(--muted); font-weight: 500; font-size: 12px; text-decoration: line-through; margin-left: 6px; }
.add-btn {
border: none;
background: var(--brand);
color: #1a1208;
font-weight: 700;
padding: 9px 14px;
border-radius: 9px;
cursor: pointer;
font-size: 14px;
transition: background .15s, transform .1s;
}
.add-btn:hover { background: var(--brand-dark); }
.add-btn:active { transform: scale(0.94); }
/* ---------- Cart drawer ---------- */
.overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,.55);
opacity: 0; pointer-events: none;
transition: opacity .2s;
z-index: 50;
}
.overlay.open { opacity: 1; pointer-events: auto; }
.drawer {
position: fixed; top: 0; right: 0;
height: 100%; width: 400px; max-width: 92vw;
background: var(--surface);
border-left: 1px solid var(--border);
transform: translateX(100%);
transition: transform .25s ease;
z-index: 60;
display: flex;
flex-direction: column;
}
.drawer.open { transform: translateX(0); }
.drawer-head {
padding: 18px 20px;
border-bottom: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
}
.drawer-head h2 { margin: 0; font-size: 18px; }
.icon-btn {
background: none; border: none; color: var(--muted);
font-size: 22px; cursor: pointer; line-height: 1;
}
.icon-btn:hover { color: var(--text); }
.cart-items { flex: 1; overflow-y: auto; padding: 12px 20px; }
.cart-empty { color: var(--muted); text-align: center; padding: 40px 0; }
.cart-row {
display: flex; gap: 12px; align-items: center;
padding: 12px 0;
border-bottom: 1px solid var(--border);
}
.cart-row .emoji {
width: 46px; height: 46px; border-radius: 10px;
background: var(--surface-2);
display: grid; place-items: center; font-size: 24px;
flex-shrink: 0;
}
.cart-row .info { flex: 1; min-width: 0; }
.cart-row .info strong { font-size: 14px; display: block; }
.cart-row .info span { font-size: 12px; color: var(--muted); }
.qty { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.qty button {
width: 24px; height: 24px; border-radius: 6px;
border: 1px solid var(--border); background: var(--surface-2);
color: var(--text); cursor: pointer; font-weight: 700;
}
.qty span { font-size: 13px; min-width: 16px; text-align: center; }
.drawer-foot {
padding: 18px 20px;
border-top: 1px solid var(--border);
}
.total-row {
display: flex; justify-content: space-between;
font-size: 16px; margin-bottom: 14px;
}
.total-row strong { font-size: 20px; }
.checkout-btn {
width: 100%;
border: none;
background: var(--accent);
color: #062018;
font-weight: 800;
padding: 14px;
border-radius: 11px;
font-size: 16px;
cursor: pointer;
transition: filter .15s;
}
.checkout-btn:hover { filter: brightness(1.08); }
.checkout-btn:disabled { opacity: .4; cursor: not-allowed; }
/* ---------- Modal (checkout) ---------- */
.modal-wrap {
position: fixed; inset: 0;
display: grid; place-items: center;
background: rgba(0,0,0,.65);
opacity: 0; pointer-events: none;
transition: opacity .2s;
z-index: 70;
padding: 20px;
}
.modal-wrap.open { opacity: 1; pointer-events: auto; }
.modal {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
width: 460px; max-width: 100%;
max-height: 90vh; overflow-y: auto;
padding: 26px;
}
.modal h2 { margin: 0 0 4px; font-size: 22px; }
.modal .sub { color: var(--muted); font-size: 14px; margin-bottom: 20px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 13px; margin-bottom: 6px; color: var(--muted); }
.field input {
width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 11px 13px;
color: var(--text);
font-size: 14px;
font-family: var(--font);
}
.field input:focus { outline: none; border-color: var(--brand); }
.row2 { display: flex; gap: 12px; }
.row2 .field { flex: 1; }
.pay-btn {
width: 100%;
border: none;
background: var(--brand);
color: #1a1208;
font-weight: 800;
padding: 14px;
border-radius: 11px;
font-size: 16px;
cursor: pointer;
margin-top: 6px;
}
.pay-btn:hover { background: var(--brand-dark); }
.pay-note { font-size: 12px; color: var(--muted); text-align: center; margin-top: 12px; }
/* success */
.success { text-align: center; padding: 10px 0; }
.success .check {
width: 70px; height: 70px; margin: 0 auto 16px;
border-radius: 50%;
background: var(--accent);
display: grid; place-items: center;
font-size: 38px; color: #062018;
animation: pop .35s ease;
}
@keyframes pop { 0% { transform: scale(0); } 70% { transform: scale(1.15); } 100% { transform: scale(1); } }
.success h2 { font-size: 24px; }
.success p { color: var(--muted); }
.order-id {
background: var(--bg);
border: 1px dashed var(--border);
border-radius: 10px;
padding: 10px;
font-family: monospace;
margin: 16px 0;
font-size: 14px;
}
/* toast */
.toast {
position: fixed; bottom: 24px; left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--surface-2);
border: 1px solid var(--border);
color: var(--text);
padding: 12px 20px;
border-radius: 999px;
font-size: 14px; font-weight: 600;
opacity: 0; pointer-events: none;
transition: opacity .2s, transform .2s;
z-index: 80;
box-shadow: 0 10px 30px rgba(0,0,0,.4);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
footer {
border-top: 1px solid var(--border);
color: var(--muted);
text-align: center;
padding: 30px 20px;
font-size: 13px;
}
</style>
</head>
<body>
<header>
<div class="nav">
<div class="logo">
<span class="mark">🔌</span>
<span>Converterland™<small>adapters die niet bestaan & ook niet werken</small></span>
</div>
<button class="cart-btn" id="openCart">
🛒 Mandje
<span class="cart-count" id="cartCount">0</span>
</button>
</div>
</header>
<section class="hero">
<span class="badge">⚡ Vandaag besteld = nooit geleverd</span>
<h1>Van <span class="hl">HDMI</span> naar <span class="hl">kippensoep</span>.<br>En alles ertussenin.</h1>
<p>Dé webshop voor onmogelijke adapters. Eén kabel voor élk probleem dat je niet hebt. Volledig nep, gloednieuw uit de fantasiefabriek.</p>
<div class="disclaimer">⚠️ Let op: dit is een parodie-webshop. Niets is echt, er wordt niets afgeschreven en er wordt zéker niets verzonden. Veel plezier!</div>
</section>
<div class="section-title">
<h2>Topverkopers</h2>
<span id="productCount"></span>
</div>
<main class="grid" id="grid"></main>
<!-- Cart drawer -->
<div class="overlay" id="overlay"></div>
<aside class="drawer" id="drawer" aria-label="Winkelmandje">
<div class="drawer-head">
<h2>Jouw mandje</h2>
<button class="icon-btn" id="closeCart" aria-label="Sluiten">×</button>
</div>
<div class="cart-items" id="cartItems"></div>
<div class="drawer-foot">
<div class="total-row">
<span>Totaal (incl. nep-BTW)</span>
<strong id="cartTotal">€0,00</strong>
</div>
<button class="checkout-btn" id="checkoutBtn" disabled>Afrekenen →</button>
</div>
</aside>
<!-- Checkout modal -->
<div class="modal-wrap" id="modalWrap">
<div class="modal" id="modalContent"></div>
</div>
<div class="toast" id="toast"></div>
<footer>
© <span id="year"></span> Converterland™ — Een product van de afdeling Onzin. Geen rechten te ontlenen, geen kabels te verwachten.
</footer>
<script>
const products = [
{ id: 1, emoji: "", name: "HDMI → Waterslang", price: 24.99, old: 39.99, desc: "Stuur 4K-beeld rechtstreeks de tuin in. Spuit je serie zó de border op.", rating: "★★★★☆ (1.204)" },
{ id: 2, emoji: "🎹", name: "Ethernet → MIDI", price: 18.50, old: 29.00, desc: "Speel pianoconcerten via je netwerkkabel. Latency: ongeveer 3 werkdagen.", rating: "★★★★★ (893)" },
{ id: 3, emoji: "🔋", name: "SATA → 9V Analoog", price: 12.95, old: 19.95, desc: "Haal je harde schijf leeg in een vierkante batterij. Voor de echte rebel.", rating: "★★★☆☆ (412)" },
{ id: 4, emoji: "🍲", name: "HDMI → Kippensoep", price: 32.00, old: 49.99, desc: "Converteert beeldsignaal naar warme, voedzame bouillon. Vega-variant op aanvraag.", rating: "★★★★★ (2.671)" },
{ id: 5, emoji: "📠", name: "USB-C → Faxrook", price: 27.75, old: 44.00, desc: "Verzend bestanden als rooksignaal. Compatibel met alle indianenstammen.", rating: "★★★★☆ (556)" },
{ id: 6, emoji: "🧦", name: "VGA → Linkersok", price: 9.99, old: 14.99, desc: "Eindelijk: je beeldscherm aansluiten op één enkele sok. Maat 38-46.", rating: "★★☆☆☆ (88)" },
{ id: 7, emoji: "☕", name: "Bluetooth → Koffie", price: 21.40, old: 33.00, desc: "Draadloos koppelen met een verse espresso. Pairing-code is altijd '0000'.", rating: "★★★★★ (1.999)" },
{ id: 8, emoji: "🌪️", name: "DisplayPort → Wind", price: 16.20, old: 25.00, desc: "Zet je framerate om in een aangenaam briesje. 144Hz = orkaankracht.", rating: "★★★★☆ (734)" },
{ id: 9, emoji: "🐌", name: "Glasvezel → Slak", price: 45.00, old: 69.99, desc: "1 Gbit/s, maar dan biologisch afbreekbaar en heel erg langzaam.", rating: "★★★☆☆ (203)" },
{ id: 10, emoji: "🧀", name: "AUX → Kaasplank", price: 14.49, old: 22.00, desc: "Audio uit één jack, kaas uit de andere. De ultieme borrel-adapter.", rating: "★★★★★ (1.420)" },
{ id: 11, emoji: "🛸", name: "RJ45 → Buitenaards", price: 99.99, old: 149.99, desc: "Verbind je router rechtstreeks met de Melkweg. Ping naar Mars: 4 minuten.", rating: "★★★★★ (42)" },
{ id: 12, emoji: "🥁", name: "Type-C → Drumsolo", price: 19.95, old: 29.95, desc: "Elke keer dat je oplaadt, krijg je een gratis drumsolo. Inclusief cimbaal.", rating: "★★★★☆ (612)" },
];
const fmt = n => "€" + n.toFixed(2).replace(".", ",");
const cart = {}; // id -> qty
// Render products
const grid = document.getElementById("grid");
document.getElementById("productCount").textContent = products.length + " absurde adapters";
grid.innerHTML = products.map(p => `
<article class="card">
<div class="thumb">${p.emoji}</div>
<div class="body">
<h3>${p.name}</h3>
<div class="rating">${p.rating}</div>
<p class="desc">${p.desc}</p>
<div class="foot">
<span class="price">${fmt(p.price)}<small>${fmt(p.old)}</small></span>
<button class="add-btn" data-id="${p.id}">In mandje</button>
</div>
</div>
</article>
`).join("");
// Elements
const overlay = document.getElementById("overlay");
const drawer = document.getElementById("drawer");
const cartItems = document.getElementById("cartItems");
const cartCount = document.getElementById("cartCount");
const cartTotal = document.getElementById("cartTotal");
const checkoutBtn = document.getElementById("checkoutBtn");
const modalWrap = document.getElementById("modalWrap");
const modalContent = document.getElementById("modalContent");
const toast = document.getElementById("toast");
let toastTimer;
function showToast(msg) {
toast.textContent = msg;
toast.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => toast.classList.remove("show"), 1800);
}
function openCart() { overlay.classList.add("open"); drawer.classList.add("open"); }
function closeCart() { overlay.classList.remove("open"); drawer.classList.remove("open"); }
document.getElementById("openCart").onclick = openCart;
document.getElementById("closeCart").onclick = closeCart;
overlay.onclick = closeCart;
function addToCart(id) {
cart[id] = (cart[id] || 0) + 1;
render();
const p = products.find(x => x.id === id);
showToast(p.emoji + " " + p.name + " toegevoegd!");
}
function changeQty(id, delta) {
cart[id] = (cart[id] || 0) + delta;
if (cart[id] <= 0) delete cart[id];
render();
}
grid.addEventListener("click", e => {
const btn = e.target.closest(".add-btn");
if (btn) addToCart(Number(btn.dataset.id));
});
function totals() {
let count = 0, sum = 0;
for (const id in cart) {
const p = products.find(x => x.id === Number(id));
count += cart[id];
sum += p.price * cart[id];
}
return { count, sum };
}
function render() {
const ids = Object.keys(cart);
const { count, sum } = totals();
cartCount.textContent = count;
cartTotal.textContent = fmt(sum);
checkoutBtn.disabled = count === 0;
if (ids.length === 0) {
cartItems.innerHTML = '<div class="cart-empty">Je mandje is leeg.<br>Tijd voor een onmisbare adapter! 🔌</div>';
return;
}
cartItems.innerHTML = ids.map(id => {
const p = products.find(x => x.id === Number(id));
return `
<div class="cart-row">
<div class="emoji">${p.emoji}</div>
<div class="info">
<strong>${p.name}</strong>
<span>${fmt(p.price)} per stuk</span>
<div class="qty">
<button data-act="dec" data-id="${p.id}"></button>
<span>${cart[p.id]}</span>
<button data-act="inc" data-id="${p.id}">+</button>
</div>
</div>
<strong>${fmt(p.price * cart[p.id])}</strong>
</div>`;
}).join("");
}
cartItems.addEventListener("click", e => {
const btn = e.target.closest("button");
if (!btn) return;
changeQty(Number(btn.dataset.id), btn.dataset.act === "inc" ? 1 : -1);
});
// ---------- Checkout ----------
function openModal() { modalWrap.classList.add("open"); }
function closeModal() { modalWrap.classList.remove("open"); }
modalWrap.addEventListener("click", e => { if (e.target === modalWrap) closeModal(); });
checkoutBtn.onclick = () => { closeCart(); renderCheckoutForm(); openModal(); };
function renderCheckoutForm() {
const { sum } = totals();
modalContent.innerHTML = `
<h2>Afrekenen 💳</h2>
<p class="sub">Vul gerust onzin in — er gebeurt tóch niets.</p>
<form id="payForm">
<div class="field">
<label>Naam</label>
<input required placeholder="Bijv. Kabel Kabelman" />
</div>
<div class="field">
<label>E-mail</label>
<input required type="email" placeholder="jij@nepmail.nl" />
</div>
<div class="field">
<label>Bezorgadres</label>
<input required placeholder="Verzinstraat 123, Fantasiestad" />
</div>
<div class="field">
<label>Kaartnummer (niet echt invullen!)</label>
<input required inputmode="numeric" placeholder="0000 0000 0000 0000" />
</div>
<div class="row2">
<div class="field">
<label>Vervaldatum</label>
<input required placeholder="MM/JJ" />
</div>
<div class="field">
<label>CVC</label>
<input required placeholder="123" />
</div>
</div>
<button class="pay-btn" type="submit">Betaal ${fmt(sum)} (nep) →</button>
<p class="pay-note">🔒 Beveiligd met nep-encryptie. Geen echte betaling.</p>
</form>
`;
document.getElementById("payForm").addEventListener("submit", e => {
e.preventDefault();
renderSuccess();
});
}
function renderSuccess() {
const { count } = totals();
const orderId = "CL-" + Math.floor(100000 + Math.random() * 900000);
modalContent.innerHTML = `
<div class="success">
<div class="check">✓</div>
<h2>Bedankt voor je nep-bestelling!</h2>
<p>${count} onmisbare adapter(s) zijn besteld bij de fantasiefabriek.</p>
<div class="order-id">Bestelnummer: ${orderId}</div>
<p>Verwachte levering: <strong>nooit</strong> 🚚💨</p>
<button class="pay-btn" id="doneBtn" style="margin-top:18px">Verder shoppen</button>
</div>
`;
// empty cart
for (const k in cart) delete cart[k];
render();
document.getElementById("doneBtn").onclick = () => { closeModal(); showToast("Mandje geleegd — tijd voor meer onzin!"); };
}
document.getElementById("year").textContent = new Date().getFullYear();
render();
</script>
</body>
</html>