feat: replace hero tabs with interactive template slider

This commit is contained in:
DanielS
2026-07-18 04:50:55 +02:00
parent 934a047586
commit 7bebcc066e

View File

@@ -1,5 +1,18 @@
---
// src/components/HeroAndLiquidGlass.astro
const heroTemplates = [
{ id: "01", name: "Der Handwerker-Klassiker", style: "Einfach & Bodenständig", layout: "boxed", design: "Brutalismus", colors: "from-[#FDFBF7] to-[#FAF7F2] text-[#2C1A11] border-[#2C1A11]/10" },
{ id: "02", name: "Dachdecker Meister", style: "Elegant & Professionell", layout: "split", design: "Glassmorphismus", colors: "from-zinc-900 to-zinc-950 text-white border-yellow-500/20" },
{ id: "03", name: "Solar & Photovoltaik", style: "Tech & Zukunft", layout: "bento", design: "SaaS-Minimalismus", colors: "from-zinc-900 to-black text-zinc-100 border-orange-500/20" },
{ id: "04", name: "Die Kanzlei", style: "Seriös & Clean", layout: "asymmetric", design: "Glassmorphismus", colors: "from-[#0B0F19] to-[#070A13] text-white border-emerald-500/20" },
{ id: "05", name: "Bio-Hofladen", style: "Rustikal & Natur", layout: "single", design: "Neomorphismus", colors: "from-[#FAF7F2] to-[#E8DCC4] text-[#4A3B32] border-[#E8DCC4]" },
{ id: "06", name: "Sanitär & Heizung", style: "Klar & Zuverlässig", layout: "bento", design: "SaaS-Minimalismus", colors: "from-white to-slate-50 text-slate-800 border-slate-200" },
{ id: "07", name: "KFZ Schnellservice", style: "Dynamisch & Direkt", layout: "split", design: "Brutalismus", colors: "from-zinc-800 to-zinc-900 text-white border-zinc-700" },
{ id: "08", name: "Schreinerei Holzart", style: "Handwerk & Präzision", layout: "boxed", design: "SaaS-Minimalismus", colors: "from-[#F5F2EB] to-[#D9D2C5] text-[#3D3A36] border-[#D9D2C5]" },
{ id: "09", name: "Steuerberater Premium", style: "Exklusiv & Diskret", layout: "bento", design: "Glassmorphismus", colors: "from-slate-900 to-slate-950 text-slate-100 border-amber-500/20" },
{ id: "10", name: "Garten- & Landschaftsbau", style: "Frisch & Modern", layout: "asymmetric", design: "Glassmorphismus", colors: "from-[#F3F7F4] to-white text-slate-800 border-emerald-200" }
];
---
<!-- Hero-Sektion: Hybrid Liquid Glass Style & Aurora Glow -->
@@ -55,94 +68,89 @@
<span class="absolute bottom-3 left-3 w-2 h-2 border-b border-l border-slate-300 dark:border-white/30"></span>
<span class="absolute bottom-3 right-3 w-2 h-2 border-b border-r border-slate-300 dark:border-white/30"></span>
<!-- Header mit Tabs -->
<div class="relative z-10">
<div class="flex justify-between items-center mb-3">
<span class="text-[9px] font-mono text-slate-400 dark:text-zinc-500 tracking-widest">LIVE PREVIEW</span>
<div class="flex gap-1">
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-red-500/60"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-yellow-500/60"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-green-500/60"></span>
</div>
</div>
<div class="flex gap-1 p-1 bg-black/5 dark:bg-white/5 rounded-xl border border-black/5 dark:border-white/5">
<button data-tab="tab-handwerk" class="hero-tab-btn flex-1 py-1.5 text-[10px] font-bold rounded-lg transition-all bg-sky-600 text-white dark:bg-sky-50 dark:text-zinc-950">Handwerk</button>
<button data-tab="tab-kanzlei" class="hero-tab-btn flex-1 py-1.5 text-[10px] font-bold rounded-lg transition-all text-slate-600 dark:text-zinc-400 hover:text-slate-900 dark:hover:text-white">Kanzlei</button>
<button data-tab="tab-solar" class="hero-tab-btn flex-1 py-1.5 text-[10px] font-bold rounded-lg transition-all text-slate-600 dark:text-zinc-400 hover:text-slate-900 dark:hover:text-white">Solar</button>
<!-- Header -->
<div class="relative z-10 flex justify-between items-center mb-3">
<span class="text-[9px] font-mono text-slate-400 dark:text-zinc-500 tracking-widest uppercase" id="hero-slider-counter">TEMPLATE 01 / 10</span>
<div class="flex gap-1">
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-red-500/60"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-yellow-500/60"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-300 dark:bg-green-500/60"></span>
</div>
</div>
<!-- Dynamic Content Area -->
<div class="my-auto relative z-10 w-full">
<!-- Tab: Handwerk -->
<div id="content-tab-handwerk" class="hero-tab-content block">
<div class="relative w-full h-44 rounded-2xl border border-yellow-500/20 bg-gradient-to-br from-zinc-900 to-zinc-950 text-white p-4 flex flex-col justify-between overflow-hidden shadow-inner">
<div class="flex justify-between items-center border-b border-white/5 pb-2">
<span class="text-[9px] font-mono opacity-60 tracking-wider">TEMPLATE 02</span>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-yellow-500/10 text-yellow-400 uppercase font-bold">Split-Screen</span>
</div>
<div class="flex-grow py-3 flex gap-2 opacity-40">
<div class="w-1/2 h-14 bg-white/10 rounded"></div>
<div class="w-1/2 h-14 bg-yellow-500/20 rounded flex flex-col justify-end p-1"><div class="h-2 w-3/4 bg-yellow-500/30 rounded"></div></div>
</div>
<div class="flex justify-between items-end pt-2 border-t border-white/5">
<div>
<h3 class="text-xs font-bold leading-none">Dachdecker Meister</h3>
<span class="text-[9px] opacity-60 mt-1 block">Elegant & Professionell</span>
<!-- Dynamic Slider Content -->
<div class="my-auto relative z-10 w-full overflow-hidden h-48">
{heroTemplates.map((item, index) => (
<div id={`hero-slide-${index}`} class={`hero-slide absolute inset-0 transition-all duration-500 flex flex-col justify-between ${index === 0 ? 'opacity-100 scale-100 pointer-events-auto' : 'opacity-0 scale-95 pointer-events-none'}`}>
<div class:list={["relative w-full h-full rounded-2xl border bg-gradient-to-br p-4 flex flex-col justify-between shadow-inner", item.colors]}>
<!-- Top bar inside preview card -->
<div class="flex justify-between items-center border-b border-current/5 pb-2">
<span class="text-[9px] font-mono opacity-60 tracking-wider">TEMPLATE {item.id}</span>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-current/10 uppercase font-bold">{item.layout}</span>
</div>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-white/5 uppercase">Anthrazit & Gold</span>
</div>
</div>
</div>
<!-- Tab: Kanzlei -->
<div id="content-tab-kanzlei" class="hero-tab-content hidden">
<div class="relative w-full h-44 rounded-2xl border border-emerald-500/20 bg-gradient-to-br from-[#0B0F19] to-[#070A13] text-white p-4 flex flex-col justify-between overflow-hidden shadow-inner">
<div class="flex justify-between items-center border-b border-white/5 pb-2">
<span class="text-[9px] font-mono opacity-60 tracking-wider">TEMPLATE 04</span>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-emerald-500/10 text-emerald-400 uppercase font-bold">Asymmetrisch</span>
</div>
<div class="flex-grow py-3 flex gap-2 opacity-40">
<div class="w-1/3 h-14 bg-white/10 rounded"></div>
<div class="w-2/3 h-10 bg-emerald-500/20 rounded"></div>
</div>
<div class="flex justify-between items-end pt-2 border-t border-white/5">
<div>
<h3 class="text-xs font-bold leading-none">Die Kanzlei</h3>
<span class="text-[9px] opacity-60 mt-1 block">Seriös & Clean</span>
<!-- Mini layout representations -->
<div class="flex-grow py-3 flex gap-2 opacity-30">
{item.layout === "bento" && (
<div class="w-full grid grid-cols-3 gap-1">
<div class="col-span-2 h-5 bg-current/20 rounded"></div>
<div class="h-5 bg-current/20 rounded"></div>
<div class="h-7 bg-current/25 rounded"></div>
<div class="col-span-2 h-7 bg-current/20 rounded"></div>
</div>
)}
{item.layout === "split" && (
<div class="w-full grid grid-cols-2 gap-2">
<div class="h-14 bg-current/20 rounded"></div>
<div class="h-14 bg-current/30 rounded flex flex-col justify-end p-1"><div class="h-1.5 w-3/4 bg-current/20 rounded"></div></div>
</div>
)}
{item.layout === "boxed" && (
<div class="w-full border border-current/20 rounded p-1 flex flex-col gap-1">
<div class="h-2 bg-current/20 rounded"></div>
<div class="h-9 bg-current/20 rounded"></div>
</div>
)}
{item.layout === "asymmetric" && (
<div class="w-full flex gap-2">
<div class="w-1/3 h-14 bg-current/25 rounded"></div>
<div class="w-2/3 h-10 bg-current/15 rounded"></div>
</div>
)}
{item.layout === "single" && (
<div class="w-full flex flex-col gap-1">
<div class="h-3 bg-current/20 rounded"></div>
<div class="h-3 bg-current/20 rounded"></div>
<div class="h-6 bg-current/20 rounded"></div>
</div>
)}
</div>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-white/5 uppercase">Smaragd-Grün</span>
</div>
</div>
</div>
<!-- Tab: Solar -->
<div id="content-tab-solar" class="hero-tab-content hidden">
<div class="relative w-full h-44 rounded-2xl border border-orange-500/20 bg-gradient-to-br from-zinc-900 to-black text-zinc-100 p-4 flex flex-col justify-between overflow-hidden shadow-inner">
<div class="flex justify-between items-center border-b border-white/5 pb-2">
<span class="text-[9px] font-mono opacity-60 tracking-wider">TEMPLATE 03</span>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-orange-500/10 text-orange-400 uppercase font-bold">Bento-Grid</span>
</div>
<div class="flex-grow py-3 grid grid-cols-3 gap-1 opacity-40">
<div class="col-span-2 h-6 bg-white/10 rounded"></div>
<div class="h-6 bg-white/10 rounded"></div>
<div class="h-8 bg-orange-500/25 rounded"></div>
<div class="col-span-2 h-8 bg-white/10 rounded"></div>
</div>
<div class="flex justify-between items-end pt-2 border-t border-white/5">
<div>
<h3 class="text-xs font-bold leading-none">Solar & Photovoltaik</h3>
<span class="text-[9px] opacity-60 mt-1 block">Tech & Zukunft</span>
<!-- Bottom info -->
<div class="flex justify-between items-end pt-2 border-t border-current/5">
<div>
<h3 class="text-xs font-bold leading-none">{item.name}</h3>
<span class="text-[9px] opacity-60 mt-1 block">{item.style}</span>
</div>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-current/5 uppercase">{item.design}</span>
</div>
<span class="text-[9px] font-mono px-1.5 py-0.5 rounded bg-white/5 uppercase">Neon-Orange</span>
</div>
</div>
</div>
))}
</div>
<!-- Footer mit Button -->
<!-- Navigation Footer -->
<div class="relative z-10 border-t border-slate-100 dark:border-white/5 pt-4 flex justify-between items-center">
<span class="text-[10px] font-mono text-slate-500 dark:text-zinc-400">TYPE: INTERACTIVE</span>
<!-- Left/Right Buttons -->
<div class="flex gap-2">
<button id="hero-slider-prev" aria-label="Vorheriges Template" class="w-8 h-8 rounded-lg bg-black/5 hover:bg-black/10 dark:bg-white/5 dark:hover:bg-white/10 flex items-center justify-center text-slate-700 dark:text-white transition-colors border border-black/5 dark:border-white/5">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="w-2.5 h-2.5 fill-current"><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg>
</button>
<button id="hero-slider-next" aria-label="Nächstes Template" class="w-8 h-8 rounded-lg bg-black/5 hover:bg-black/10 dark:bg-white/5 dark:hover:bg-white/10 flex items-center justify-center text-slate-700 dark:text-white transition-colors border border-black/5 dark:border-white/5">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" class="w-2.5 h-2.5 fill-current"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s-32.8-12.5-45.3 0l192 192z"/></svg>
</button>
</div>
<a href="/templates" class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-sky-600 hover:bg-sky-700 dark:bg-sky-500/10 dark:hover:bg-sky-500/20 text-white dark:text-sky-400 font-bold text-[10px] uppercase tracking-wider rounded-lg border border-transparent dark:border-sky-500/20 transition-colors">
Alle Templates
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="w-2.5 h-2.5 fill-current" aria-hidden="true"><path d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"/></svg>
@@ -415,36 +423,35 @@
}
});
// Hero Tab Switcher
const tabButtons = document.querySelectorAll('.hero-tab-btn');
const tabContents = document.querySelectorAll('.hero-tab-content');
// Hero Template Slider
const slides = document.querySelectorAll('.hero-slide');
const prevBtn = document.getElementById('hero-slider-prev');
const nextBtn = document.getElementById('hero-slider-next');
const counter = document.getElementById('hero-slider-counter');
let currentIdx = 0;
const totalSlides = slides.length;
tabButtons.forEach(btn => {
btn.addEventListener('click', () => {
const activeTab = btn.getAttribute('data-tab');
function updateSlider(newIdx) {
// Hide current slide
slides[currentIdx].classList.remove('opacity-100', 'scale-100', 'pointer-events-auto');
slides[currentIdx].classList.add('opacity-0', 'scale-95', 'pointer-events-none');
// Reset buttons
tabButtons.forEach(b => {
b.classList.remove('bg-sky-600', 'text-white', 'dark:bg-sky-500', 'dark:text-zinc-950');
b.classList.add('text-slate-600', 'dark:text-zinc-400', 'hover:text-slate-900', 'dark:hover:text-white');
});
// Update index
currentIdx = (newIdx + totalSlides) % totalSlides;
// Active button
btn.classList.add('bg-sky-600', 'text-white', 'dark:bg-sky-500', 'dark:text-zinc-950');
btn.classList.remove('text-slate-600', 'dark:text-zinc-400', 'hover:text-slate-900', 'dark:hover:text-white');
// Show new slide
slides[currentIdx].classList.remove('opacity-0', 'scale-95', 'pointer-events-none');
slides[currentIdx].classList.add('opacity-100', 'scale-100', 'pointer-events-auto');
// Reset contents
tabContents.forEach(c => {
c.classList.add('hidden');
c.classList.remove('block');
});
// Update counter text
if (counter) {
const templateNum = String(currentIdx + 1).padStart(2, '0');
counter.textContent = `TEMPLATE ${templateNum} / ${totalSlides}`;
}
}
// Active content
const targetContent = document.getElementById(`content-${activeTab}`);
if (targetContent) {
targetContent.classList.remove('hidden');
targetContent.classList.add('block');
}
});
});
if (prevBtn && nextBtn) {
prevBtn.addEventListener('click', () => updateSlider(currentIdx - 1));
nextBtn.addEventListener('click', () => updateSlider(currentIdx + 1));
}
</script>