@@ -1258,6 +1258,7 @@ class FastSearchCard extends HTMLElement {
12581258 gap: 12px;
12591259 opacity: 0;
12601260 transform: translateX(20px);
1261+ filter: url(#categoryGooey);
12611262 }
12621263
12631264 /* Mobile: Category-Buttons zentrieren */
@@ -4588,9 +4589,59 @@ class FastSearchCard extends HTMLElement {
45884589 height: 24px;
45894590 transition: all 0.2s ease;
45904591 }
4592+
4593+
4594+
4595+ /* NEU: SVG Gooey Filter für Liquid Animation */
4596+ .gooey-filter {
4597+ position: absolute;
4598+ width: 0;
4599+ height: 0;
4600+ pointer-events: none;
4601+ }
4602+
4603+ /* Blob Animation Container */
4604+ .blob-container {
4605+ position: absolute;
4606+ top: 0;
4607+ right: 0;
4608+ width: 400px;
4609+ height: 72px;
4610+ pointer-events: none;
4611+ z-index: 5;
4612+ display: none;
4613+ }
4614+
4615+ .liquid-blob {
4616+ position: absolute;
4617+ background: rgba(255, 255, 255, 0.15);
4618+ backdrop-filter: blur(var(--glass-blur-amount));
4619+ border-radius: 50%;
4620+ opacity: 0;
4621+ will-change: transform, opacity;
4622+ }
4623+
4624+ /* Blob-spezifische Größen */
4625+ .blob-1 { width: 72px; height: 72px; }
4626+ .blob-2 { width: 72px; height: 72px; }
4627+ .blob-3 { width: 72px; height: 72px; }
4628+ .blob-4 { width: 72px; height: 72px; }
4629+ .blob-5 { width: 72px; height: 72px; }
45914630
45924631 </style>
45934632
4633+ <!-- NEU: SVG Filter für Gooey Effect -->
4634+ <svg class="gooey-filter">
4635+ <defs>
4636+ <filter id="categoryGooey" x="-50%" y="-50%" width="200%" height="200%">
4637+ <feGaussianBlur in="SourceGraphic" stdDeviation="8"/>
4638+ <feComponentTransfer>
4639+ <feFuncA type="discrete" tableValues="0 .7 1"/>
4640+ </feComponentTransfer>
4641+ </filter>
4642+ </defs>
4643+ </svg>
4644+
45944645 <div class="main-container">
45954646 <div class="search-row">
45964647 <div class="search-panel glass-panel">
@@ -4750,6 +4801,16 @@ class FastSearchCard extends HTMLElement {
47504801 <div class="detail-panel glass-panel">
47514802 </div>
47524803
4804+ <!-- NEU: Blob Container für Liquid Animation -->
4805+ <div class="blob-container" id="blobContainer">
4806+ <div class="liquid-blob blob-1"></div>
4807+ <div class="liquid-blob blob-2"></div>
4808+ <div class="liquid-blob blob-3"></div>
4809+ <div class="liquid-blob blob-4"></div>
4810+ <div class="liquid-blob blob-5"></div>
4811+ </div>
4812+
4813+
47534814 <div class="category-buttons">
47544815 <button class="category-button glass-panel active" data-category="devices" title="Geräte">
47554816 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -4987,8 +5048,8 @@ class FastSearchCard extends HTMLElement {
49875048 }
49885049
49895050 showCategoryButtons() {
4990- this.collapsePanel(); // <-- HINZUGEFÜGTE ZEILE
4991-
5051+ this.collapsePanel();
5052+
49925053 // NEU: Search-Wrapper auf Mobile verstecken
49935054 if (this.isMobile()) {
49945055 const searchWrapper = this.shadowRoot.querySelector('.search-panel');
@@ -4997,10 +5058,10 @@ class FastSearchCard extends HTMLElement {
49975058 }
49985059 }
49995060
5000- const categoryButtons = this.shadowRoot.querySelector('.category-buttons');
50015061 this.isMenuView = true;
5002- categoryButtons.classList.add('visible');
5003- categoryButtons.animate([{ opacity: 0, transform: 'translateX(20px) scale(0.9)' }, { opacity: 1, transform: 'translateX(0) scale(1)' }], { duration: 400, easing: 'cubic-bezier(0.16, 1, 0.3, 1)', fill: 'forwards' });
5062+
5063+ // 🌊 NEUE LIQUID ANIMATION statt der alten Animation
5064+ this.startLiquidCategoryAnimation();
50045065 }
50055066
50065067 hideCategoryButtons() {
@@ -5041,6 +5102,110 @@ class FastSearchCard extends HTMLElement {
50415102 this.hideCategoryButtons();
50425103 }
50435104
5105+ // 🌊 LIQUID ANIMATION METHODEN
5106+
5107+ createBlobAnimation() {
5108+ const blobContainer = this.shadowRoot.querySelector('#blobContainer');
5109+ const blobs = blobContainer.querySelectorAll('.liquid-blob');
5110+
5111+ // Alle Blobs zurücksetzen
5112+ blobs.forEach(blob => {
5113+ blob.style.opacity = '0';
5114+ blob.style.transform = 'scale(0) translateX(0px)';
5115+ });
5116+
5117+ return { blobContainer, blobs };
5118+ }
5119+
5120+ animateBlobEmergence(blobs) {
5121+ return new Promise((resolve) => {
5122+ // Schritt 1: Ersten Blob erscheinen lassen
5123+ const firstBlob = blobs[0];
5124+ firstBlob.style.display = 'block';
5125+ firstBlob.style.left = '0px';
5126+ firstBlob.style.top = '0px';
5127+
5128+ firstBlob.animate([
5129+ { opacity: 0, transform: 'scale(0) translateX(0px)' },
5130+ { opacity: 1, transform: 'scale(1) translateX(0px)' }
5131+ ], {
5132+ duration: 300,
5133+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
5134+ fill: 'forwards'
5135+ }).finished.then(() => {
5136+ setTimeout(resolve, 100);
5137+ });
5138+ });
5139+ }
5140+
5141+ animateBlobSegmentation(blobs) {
5142+ return new Promise((resolve) => {
5143+ // Alle 5 Blobs zu ihren finalen Positionen animieren
5144+ const positions = [
5145+ { x: 0, y: 0 }, // devices
5146+ { x: 84, y: 0 }, // scripts
5147+ { x: 168, y: 0 }, // automations
5148+ { x: 252, y: 0 }, // scenes
5149+ { x: 336, y: 0 } // custom
5150+ ];
5151+
5152+ const animations = Array.from(blobs).map((blob, index) => {
5153+ const pos = positions[index];
5154+
5155+ return blob.animate([
5156+ {
5157+ opacity: index === 0 ? 1 : 0,
5158+ transform: `scale(${index === 0 ? 1 : 0}) translateX(0px)`
5159+ },
5160+ {
5161+ opacity: 1,
5162+ transform: `scale(1) translateX(${pos.x}px)`
5163+ }
5164+ ], {
5165+ duration: 400,
5166+ delay: index * 80,
5167+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
5168+ fill: 'forwards'
5169+ });
5170+ });
5171+
5172+ Promise.all(animations.map(anim => anim.finished)).then(() => {
5173+ setTimeout(resolve, 200);
5174+ });
5175+ });
5176+ }
5177+
5178+ startLiquidCategoryAnimation() {
5179+ const { blobContainer, blobs } = this.createBlobAnimation();
5180+
5181+ // Blob-Container anzeigen
5182+ blobContainer.style.display = 'block';
5183+
5184+ // Starte Animations-Kette
5185+ this.animateBlobEmergence(blobs)
5186+ .then(() => this.animateBlobSegmentation(blobs))
5187+ .then(() => this.materialiseCategoryButtons());
5188+ }
5189+
5190+ materialiseCategoryButtons() {
5191+ const categoryButtons = this.shadowRoot.querySelector('.category-buttons');
5192+ const blobContainer = this.shadowRoot.querySelector('#blobContainer');
5193+
5194+ // Category-Buttons anzeigen und Blobs verstecken
5195+ categoryButtons.classList.add('visible');
5196+ blobContainer.style.display = 'none';
5197+
5198+ // Finale Category-Button Animation
5199+ categoryButtons.animate([
5200+ { opacity: 0, transform: 'translateX(20px) scale(0.9)' },
5201+ { opacity: 1, transform: 'translateX(0) scale(1)' }
5202+ ], {
5203+ duration: 300,
5204+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
5205+ fill: 'forwards'
5206+ });
5207+ }
5208+
50445209 handleSubcategorySelect(selectedChip) {
50455210 let subcategory = selectedChip.dataset.subcategory;
50465211 if (subcategory === this.activeSubcategory && subcategory !== 'all') {
0 commit comments