v4 Kontrollzentrum: 6 Länder (DE/AT/CH/NL/PL/DK), Währungs-aware, eBay/Retoure + Shop-Seriosität, Preis-Strip, Wetter-Banner (Open-Meteo)+Quellen, availability-first Home, Animationen, Länder-Scope, Preiswecker

This commit is contained in:
2026-06-28 06:47:30 +00:00
parent 600fcfe97d
commit 0915e0988b
16 changed files with 3655 additions and 129 deletions
+83 -61
View File
@@ -2,102 +2,124 @@
import Base from '../layouts/Base.astro';
import ProductCard from '../components/ProductCard.astro';
import { allProducts } from '../lib/pricing';
import WeatherBanner from '../components/WeatherBanner.astro';
const top = allProducts.filter(p => p.tier === 'A').slice(0,3);
const jsonld = {'@context':'https://schema.org','@type':'WebSite',name:'Kühlfinder',url:'https://kuehlfinder.de',
description:'Finde, wo es gerade Klimageräte in Baumärkten und Elektromärkten gibt mit Prognose, Preis-Check und Alarm.'};
description:'Finde live, wo es Klimageräte gibt Baumärkte & Elektromärkte in DE, AT, CH, NL, PL, DK, plus Online/eBay mit Prognose, Preis-Check und Alarm.'};
const Pin='<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M12 21s7-5.6 7-11a7 7 0 1 0-14 0c0 5.4 7 11 7 11Z"/><circle cx="12" cy="10" r="2.5"/></svg>';
const Compass='<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="9"/><path d="m15.5 8.5-2 5-5 2 2-5 5-2Z"/></svg>';
const Bell='<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M6 9a6 6 0 1 1 12 0c0 5 2 6 2 6H4s2-1 2-6Z"/><path d="M10 19a2 2 0 0 0 4 0"/></svg>';
---
<Base title="Kühlfinder Wo gibt es gerade ein Klimagerät? Live-Verfügbarkeit in DE" description="Live-Bestand von Klimageräten in Baumärkten (OBI, Toom, Bauhaus …) und Elektromärkten (MediaMarkt, Saturn …) plus Amazon/idealo mit Verfügbarkeits-Prognose, Preis-Check und Alarm." jsonld={jsonld}>
<Base title="Kühlfinder Wo gibt es gerade ein Klimagerät? Live-Verfügbarkeit (DE/AT/CH/NL/PL/DK)" description="Live-Bestand von Klimageräten in Baumärkten & Elektromärkten in Deutschland und Nachbarländern, plus Online, Amazon & eBay mit Prognose, Preis-Check gegen Wucher und Alarm.">
<section class="hero"><div class="wrap">
<span class="eyebrow"><span class="dot ok"></span>Live-Verfügbarkeit · eigener Scraper</span>
<WeatherBanner />
<span class="eyebrow" style="margin-top:1rem"><span class="dot ok live"></span>Live-Verfügbarkeit · eigener Scraper</span>
<h1>Wo gibt es gerade ein&nbsp;Klimagerät?</h1>
<p class="lead">Klimageräte sind bei Hitze überall vergriffen. Kühlfinder zeigt dir <strong>live, welcher Markt in deiner Nähe eins auf Lager hat</strong> Baumärkte und Elektromärkte mit Verfügbarkeits-Prognose, Preis-Check gegen Wucher und Alarm, sobald wieder was da ist.</p>
<p class="lead">Bei Hitze ist alles vergriffen. Kühlfinder ist dein Kontrollzentrum: <strong>live sehen, welcher Markt in der Nähe eins auf Lager hat</strong> Baumärkte, Elektromärkte, Online &amp; eBay mit Prognose, Preis-Check gegen Wucher und Alarm. <em>Die nächste Hitzewelle kommt bestimmt.</em></p>
<form class="herobar" action="/karte" method="get">
<input name="plz" inputmode="numeric" placeholder="PLZ oder Ort eingeben …" aria-label="PLZ oder Ort" />
<input name="plz" inputmode="numeric" placeholder="PLZ oder Ort …" aria-label="PLZ oder Ort" />
<button class="btn" type="submit">Verfügbarkeit zeigen</button>
<a class="btn ghost" href="/karte" id="locbtn">In meiner Nähe</a>
</form>
<div class="pills" id="livepills">
<span class="pill-stat"><b id="p-ac">…</b> Märkte mit Klimagerät jetzt</span>
<span class="pill-stat"><b id="p-total">…</b> Märkte überwacht</span>
<span class="pill-stat"><b id="p-chains">10</b> Ketten · Baumarkt + Elektro</span>
<div class="livewrap reveal">
<div class="pills">
<span class="pill-stat"><b class="num" id="p-ac" data-count="0">…</b>&nbsp;Märkte mit Klimagerät jetzt</span>
<span class="pill-stat"><b class="num" id="p-total" data-count="0">…</b>&nbsp;Märkte überwacht</span>
<span class="pill-stat"><b class="num">6</b>&nbsp;Länder · <span id="p-chains">…</span> Ketten</span>
</div>
<div class="livecard card">
<div class="lc-head"><span class="dot ok live"></span> Gerade verfügbar</div>
<ul class="livelist" id="livelist"><li class="skel" style="height:40px"></li><li class="skel" style="height:40px"></li><li class="skel" style="height:40px"></li></ul>
<a class="btn sm" href="/karte">Alle auf der Karte →</a>
</div>
</div>
</div></section>
<section class="wrap">
<div class="features">
<a class="feature" href="/karte">
<div class="ic"><i class="ti">◎</i></div>
<h3>Live-Karte</h3>
<p class="muted">Alle Märkte mit aktuellem Bestand auf einen Blick filterbar nach Modell, Kette und Umkreis.</p>
</a>
<a class="feature" href="/finder">
<div class="ic">◆</div>
<h3>60-Sekunden-Finder</h3>
<p class="muted">Welches Gerät passt zu deinem Raum? Ehrliche Empfehlung nur echte Kompressorgeräte.</p>
</a>
<a class="feature" href="/alarm">
<div class="ic">◔</div>
<h3>Prognose &amp; Alarm</h3>
<p class="muted">Wir schätzen, wo die Chance in 7 Tagen am höchsten ist und melden uns per Mail/Telegram.</p>
</a>
<a class="feature reveal" href="/karte"><div class="ic" set:html={Pin}></div><h3>Live-Karte</h3><p class="muted">Alle Märkte mit Bestand auf einen Blick Modell, Kette, Land &amp; Umkreis filtern.</p></a>
<a class="feature reveal" data-d="1" href="/finder"><div class="ic" set:html={Compass}></div><h3>60-Sekunden-Finder</h3><p class="muted">Welches Gerät passt zu deinem Raum? Nur echte Kompressorgeräte.</p></a>
<a class="feature reveal" data-d="2" href="/alarm"><div class="ic" set:html={Bell}></div><h3>Prognose &amp; Alarm</h3><p class="muted">Wir schätzen, wo die Chance in 7 Tagen am höchsten ist Mail &amp; Telegram.</p></a>
</div>
</section>
<section class="wrap"><div class="band reveal">
<div>
<h2>Vergriffen? Wir warnen vor Wucher.</h2>
<p class="muted" style="max-width:42rem">Bei Knappheit verlangen Drittanbieter auf Amazon &amp; eBay schnell das Mehrfache. Kühlfinder kennt den üblichen Preis, zeigt <strong>günstigsten und teuersten</strong> Anbieter, prüft die <strong>Seriosität der Shops</strong> und markiert Wucher.</p>
<div class="bandcta"><a class="btn" href="/karte">Zur Live-Karte</a><a class="btn ghost" href="/portasplit">PortaSplit &amp; Alternativen</a></div>
</div>
<div class="band-card card">
<div class="bc-row ok"><span>eBay günstigster</span><b class="num">607 €</b></div>
<div class="bc-row"><span>Üblicher Preis</span><b class="num">799 €</b></div>
<div class="bc-row danger"><span>⚠ eBay/Marketplace-Wucher</span><b class="num">2.999 €</b></div>
</div>
</div></section>
<section class="wrap">
<div class="section-head"><div><span class="kicker"><span class="u"></span>Grenzregionen</span><h2 style="margin:.2rem 0 0">Auch im Nachbarland verfügbar</h2></div></div>
<div class="countries reveal">
<span class="cflag"><span class="flag">🇩🇪</span> Deutschland</span>
<span class="cflag"><span class="flag">🇦🇹</span> Österreich</span>
<span class="cflag"><span class="flag">🇨🇭</span> Schweiz</span>
<span class="cflag"><span class="flag">🇳🇱</span> Niederlande</span>
<span class="cflag"><span class="flag">🇵🇱</span> Polen</span>
<span class="cflag"><span class="flag">🇩🇰</span> Dänemark</span>
</div>
</section>
<section class="wrap">
<div class="section-head">
<div><span class="kicker"><span class="u"></span>Kuratiert</span><h2 style="margin:.2rem 0 0">Beliebte Geräte und wo es sie gibt</h2></div>
<a class="btn ghost sm" href="/geraete">Alle Geräte &amp; Vergleich</a>
</div>
<div class="grid cards3">{top.map(p => <ProductCard product={p} />)}</div>
<div class="section-head"><div><span class="kicker"><span class="u"></span>Kuratiert</span><h2 style="margin:.2rem 0 0">Beliebte Geräte und wo es sie gibt</h2></div><a class="btn ghost sm" href="/geraete">Alle Geräte</a></div>
<div class="grid cards3">{top.map((p,i) => <div class="reveal" data-d={String(i)}><ProductCard product={p} /></div>)}</div>
</section>
<section class="wrap"><div class="band">
<div>
<h2>Vergriffen? Wir warnen vor Wucher.</h2>
<p class="muted" style="max-width:42rem">Bei Knappheit verlangen Drittanbieter (z. B. Amazon-Marketplace) schnell das Mehrfache. Kühlfinder kennt den üblichen Preis und markiert Wucher und schlägt dir wohnungstaugliche Alternativen vor, die wirklich kühlen.</p>
<div class="bandcta"><a class="btn" href="/karte">Zur Live-Karte</a><a class="btn ghost" href="/portasplit">PortaSplit &amp; Alternativen</a></div>
</div>
<div class="band-card card">
<div class="bc-row"><span>Üblicher Preis</span><b class="num">799 €</b></div>
<div class="bc-row danger"><span>⚠ Marketplace-Wucher</span><b class="num">2.999 €</b></div>
<div class="bc-row ok"><span>Fair ab</span><b class="num">699 €</b></div>
</div>
</div></section>
<section class="wrap"><div class="split">
<div class="card"><h2>So funktioniert's</h2>
<ol class="steps"><li>PLZ eingeben oder Standort nutzen.</li><li>Karte zeigt Märkte mit Bestand + Prognose.</li><li>Hingehen, oder Alarm setzen für später.</li></ol>
</div>
<div class="card warm"><h2>Hitzeschutz statt Panik</h2>
<p class="muted">Hitzewellen nehmen zu. Gute, effiziente Kühlung kann Hitzeschutz sein mit Quellen statt Alarmismus.</p>
<a class="btn ghost" href="/hitzeschutz">Klima &amp; Hitzeschutz</a>
</div>
<div class="card reveal"><h2>So funktioniert's</h2><ol class="steps"><li>PLZ eingeben oder Standort nutzen.</li><li>Karte zeigt Märkte mit Bestand + Prognose.</li><li>Hingehen oder Alarm/Preiswecker setzen.</li></ol></div>
<div class="card warm reveal" data-d="1"><h2>Hitzeschutz statt Panik</h2><p class="muted">Hitzewellen nehmen zu. Gute, effiziente Kühlung kann Hitzeschutz sein mit Quellen statt Alarmismus.</p><a class="btn ghost" href="/hitzeschutz">Klima &amp; Hitzeschutz</a></div>
</div></section>
</Base>
<style>
.hero{background:var(--grad-hero);padding:3.4rem 0 2.6rem}
.hero{background:var(--grad-hero);padding:3.4rem 0 2.8rem}
.hero h1{font-size:clamp(2.3rem,6vw,4rem);max-width:18ch;margin-top:.6rem}
.hero .lead{font-size:1.18rem;max-width:46rem;color:var(--ink-2)}
.herobar{display:flex;gap:.6rem;margin:1.4rem 0 1rem;max-width:520px}
.herobar input{flex:1;font-family:var(--font-body);font-size:1rem;padding:.85rem 1.1rem;border:1px solid var(--line);border-radius:999px;background:#fff;box-shadow:var(--shadow-card)}
.hero .lead{font-size:1.15rem;max-width:48rem;color:var(--ink-2)}
.hero .lead em{color:var(--petrol-deep);font-style:normal;font-weight:600}
.herobar{display:flex;gap:.6rem;margin:1.4rem 0 1.4rem;max-width:640px;flex-wrap:wrap}
.herobar input{flex:1;min-width:180px;font-family:var(--font-body);font-size:1rem;padding:.85rem 1.1rem;border:1px solid var(--line);border-radius:999px;background:#fff;box-shadow:var(--shadow-card)}
.herobar input:focus{border-color:var(--petrol)}
.pills{display:flex;gap:.6rem;flex-wrap:wrap}
section.wrap{margin-top:2.6rem}
.livewrap{display:grid;grid-template-columns:1fr 320px;gap:1.2rem;align-items:start;margin-top:.4rem}
.pills{display:flex;gap:.6rem;flex-wrap:wrap;align-content:start}
.livecard{display:flex;flex-direction:column;gap:.6rem;padding:1rem}
.lc-head{display:flex;align-items:center;gap:.5rem;font-weight:600;font-size:.9rem}
.livelist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.1rem}
.livelist li{display:flex;justify-content:space-between;align-items:center;gap:.5rem;padding:.45rem .1rem;border-bottom:1px solid var(--line);font-size:.88rem}
.livelist .lm{font-weight:600}.livelist .lc{font-size:.78rem;color:var(--slate)}
.livelist .lp{font-family:var(--mono);font-size:.82rem;color:var(--petrol-deep)}
section.wrap{margin-top:2.8rem}
.features{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}
.features .feature{text-decoration:none;color:var(--ink)} .features h3{margin:.2rem 0}
.features .feature{text-decoration:none;color:var(--ink)}.features h3{margin:.2rem 0}
.features .ic{color:var(--petrol-deep)}
.cards3{grid-template-columns:repeat(3,1fr)}
.band{display:grid;grid-template-columns:1.6fr 1fr;gap:1.5rem;align-items:center;background:var(--petrol-soft);border-radius:20px;padding:1.8rem}
.bandcta{display:flex;gap:.6rem;margin-top:1rem;flex-wrap:wrap}
.band-card{display:flex;flex-direction:column;gap:.5rem}
.band-card{display:flex;flex-direction:column;gap:.4rem}
.bc-row{display:flex;justify-content:space-between;align-items:center;padding:.5rem .2rem;border-bottom:1px solid var(--line)}
.bc-row b{font-size:1.1rem}.bc-row.danger b{color:var(--danger)}.bc-row.ok b{color:var(--ok-dot)}
.countries{display:flex;gap:.6rem;flex-wrap:wrap}
.cflag{display:inline-flex;align-items:center;gap:.5rem;background:var(--card);border:1px solid var(--line);border-radius:999px;padding:.45rem .9rem;box-shadow:var(--shadow-card);font-size:.9rem;font-weight:500}
.split{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.card.warm{background:var(--warm-bg)}
.steps{margin:.4rem 0 0;padding-left:1.2rem}.steps li{margin:.3rem 0}
.ic i{font-style:normal}
@media(max-width:820px){.features,.cards3,.split{grid-template-columns:1fr}.band{grid-template-columns:1fr}}
@media(max-width:860px){.livewrap{grid-template-columns:1fr}.features,.cards3,.split{grid-template-columns:1fr}.band{grid-template-columns:1fr}}
</style>
<script>
const euro=(n,c)=>n==null?'':new Intl.NumberFormat('de-DE',{style:'currency',currency:c||'EUR',maximumFractionDigits:0}).format(n);
document.getElementById('locbtn')?.addEventListener('click',e=>{ if(navigator.geolocation){ /* Karte hat eigene Standortfunktion */ } });
fetch('/data/monitor.json').then(r=>r.json()).then(d=>{
document.getElementById('p-ac').textContent=(d.stats.withAC??'').toLocaleString('de-DE');
document.getElementById('p-total').textContent=(d.stats.storesTotal??'').toLocaleString('de-DE');
const ac=document.getElementById('p-ac'), tot=document.getElementById('p-total');
ac.setAttribute('data-count', d.stats.withAC); ac.removeAttribute('data-done');
tot.setAttribute('data-count', d.stats.storesTotal); tot.removeAttribute('data-done');
const chains=new Set(d.stores.map(s=>s.c)); document.getElementById('p-chains').textContent=chains.size;
window.kfAnim && window.kfAnim();
const avail=d.stores.filter(s=>s.any.a && s.any.minP).sort(()=>Math.random()-0.5).slice(0,6);
document.getElementById('livelist').innerHTML = avail.map(s=>`<li><span><span class="flag">${s.flag||''}</span> <span class="lm">${s.c}</span> <span class="lc">${s.ci}</span></span><span class="lp">${euro(s.any.minP,s.cur)}</span></li>`).join('') || '<li class="lc">Aktuell sehr knapp Alarm setzen lohnt sich.</li>';
}).catch(()=>{});
</script>