@@ -1254,18 +1254,12 @@ class FastSearchCard extends HTMLElement {
12541254
12551255 .category-buttons {
12561256 display: none; /* Wird per JS auf 'flex' gesetzt */
1257- flex-direction: row;
1258- gap: 0; /* WICHTIG: Kein Gap für Gooey-Effekt */
1259- opacity: 1; /* Opacity wird nicht mehr animiert */
1260- transform: none; /* Kein Transform mehr */
1261- filter: url(#categoryGooey); /* ✅ BEHALTEN */
1262-
1263- /* WICHTIG für die Animation */
1264- position: relative; /* Positionierungs-Kontext für die Buttons */
1265- width: 72px; /* Startbreite = 1 Button */
1257+ align-items: center; /* NEU: Zentriert die Buttons vertikal */
1258+ position: relative; /* WICHTIG: Kontext für die absoluten Buttons */
12661259 height: 72px;
1267- padding: 0;
1260+ width: 72px; /* Startbreite = 1 Button */
12681261 will-change: width, filter;
1262+ /* Filter wird per JS hinzugefügt und entfernt */
12691263 }
12701264
12711265 /* Mobile: Category-Buttons zentrieren */
@@ -1319,6 +1313,11 @@ class FastSearchCard extends HTMLElement {
13191313 stroke-linecap: round;
13201314 stroke-linejoin: round;
13211315 transition: all 0.2s ease;
1316+
1317+ /* NEU: Für die Animation hinzufügen */
1318+ opacity: 0;
1319+ transform: scale(0.8);
1320+ will-change: opacity, transform;
13221321 }
13231322
13241323 .category-button.active svg {
@@ -4615,18 +4614,10 @@ class FastSearchCard extends HTMLElement {
46154614 <!-- ERSETZEN Sie den bestehenden SVG Filter mit diesem: -->
46164615 <svg class="gooey-filter">
46174616 <defs>
4618- <filter id="categoryGooey" x="-50%" y="-50%" width="200%" height="200%">
4619- <feGaussianBlur in="SourceGraphic" stdDeviation="15"/>
4620- <feComponentTransfer>
4621- <feFuncA type="discrete" tableValues="0 .5 1"/>
4622- </feComponentTransfer>
4623- </filter>
4624- <!-- NEU: Filter für Suchleiste Morphing -->
4625- <filter id="searchMorph" x="-20%" y="-20%" width="140%" height="140%">
4626- <feGaussianBlur in="SourceGraphic" stdDeviation="12"/>
4627- <feComponentTransfer>
4628- <feFuncA type="discrete" tableValues="0 .7 1"/>
4629- </feComponentTransfer>
4617+ <filter id="categoryGooey">
4618+ <feGaussianBlur in="SourceGraphic" stdDeviation="15" result="blur" />
4619+ <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="gooey" />
4620+ <feComposite in="SourceGraphic" in2="gooey" operator="atop"/>
46304621 </filter>
46314622 </defs>
46324623 </svg>
@@ -5032,58 +5023,77 @@ class FastSearchCard extends HTMLElement {
50325023
50335024 async showCategoryButtons() {
50345025 this.collapsePanel();
5035-
50365026 if (this.isMobile()) {
50375027 const searchWrapper = this.shadowRoot.querySelector('.search-panel');
50385028 if (searchWrapper) {
50395029 searchWrapper.style.display = 'none';
50405030 }
50415031 }
5042-
50435032 this.isMenuView = true;
50445033
5045- // --- NEUE, ELEGANTE SPOTLIGHT ANIMATION ---
5034+ // --- NEUE SPOTLIGHT ANIMATION ---
5035+
50465036 const categoryButtonsContainer = this.shadowRoot.querySelector('.category-buttons');
50475037 const buttons = Array.from(categoryButtonsContainer.querySelectorAll('.category-button'));
5038+ // Wichtig: Wir brauchen den Weichzeichner im SVG-Filter, um ihn zu animieren
5039+ const gooeyFilter = this.shadowRoot.querySelector('#categoryGooey feGaussianBlur');
5040+
5041+ if (!categoryButtonsContainer || buttons.length === 0 || !gooeyFilter) {
5042+ console.error("Animations-Elemente nicht gefunden.");
5043+ return;
5044+ }
50485045
5049- // 1. Vorbereitung: Container und Buttons für Animation vorbereiten
5050- categoryButtonsContainer.classList.add('visible'); // Container sichtbar machen
5051- categoryButtonsContainer.style.filter = 'url(#categoryGooey)'; // Gooey-Filter aktivieren
5046+ // --- Phase 1: Morphing & Trennung (Bild 1-6) ---
5047+
5048+ // 1. Vorbereitung
5049+ categoryButtonsContainer.classList.add('visible');
5050+ categoryButtonsContainer.style.filter = 'url(#categoryGooey)';
5051+ gooeyFilter.setAttribute('stdDeviation', '15'); // Weichzeichner aktivieren
50525052
5053- // Alle Buttons am Anfang des Containers positionieren und unsichtbar machen
50545053 buttons.forEach(btn => {
5055- btn.style.transform = 'translateX(0px) scale(0)';
5056- btn.style.opacity = '0';
5054+ btn.style.transform = 'translateX(0px) scale(1)';
5055+ btn.style.opacity = '1';
5056+ btn.querySelector('svg').style.opacity = '0'; // Icons bleiben unsichtbar
50575057 });
50585058
5059- // 2. Der "Wurm" wächst: Container auf volle Breite animieren
5060- const containerWidth = buttons.length * 72 + (buttons.length - 1) * 12; // 72px pro Button + 12px Abstand
5061- const containerAnimation = categoryButtonsContainer.animate([
5062- { width: '72px' },
5063- { width: `${containerWidth}px` }
5064- ], {
5065- duration: 400,
5066- easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
5067- fill: 'forwards'
5068- });
5059+ // 2. Der "Wurm" wächst (Bild 2-3)
5060+ const containerWidth = buttons.length * 72 + (buttons.length - 1) * 12;
5061+ const containerAnimation = categoryButtonsContainer.animate(
5062+ { width: [`72px`, `${containerWidth}px`] },
5063+ { duration: 350, easing: 'cubic-bezier(0.4, 0, 0.2, 1)', fill: 'forwards' }
5064+ );
50695065 await containerAnimation.finished;
50705066
5071- // 3. Die "Teilung": Buttons zu ihren finalen Positionen animieren
5072- const animations = buttons.map((btn, index) => {
5073- const finalX = index * (72 + 12); // Finale X-Position
5074- return btn.animate([
5075- { transform: 'translateX(0px) scale(1)', opacity: 1 },
5076- { transform: `translateX(${finalX}px) scale(1)`, opacity: 1 }
5077- ], {
5078- duration: 600,
5079- delay: index * 60, // Gestaffelter Start für flüssigen Effekt
5080- easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
5081- fill: 'forwards'
5082- });
5067+ // 3. Die Trennung der "Tropfen" (Bild 4-6)
5068+ const separationAnimations = buttons.map((btn, index) => {
5069+ const finalX = index * (72 + 12);
5070+ return btn.animate(
5071+ { transform: [`translateX(0px)`, `translateX(${finalX}px)`] },
5072+ { duration: 500, delay: index * 50, easing: 'cubic-bezier(0.4, 0, 0.2, 1)', fill: 'forwards' }
5073+ );
50835074 });
5084- await Promise.all(animations.map(a => a.finished));
5075+ await Promise.all(separationAnimations.map(a => a.finished));
5076+
5077+ // --- Phase 2: Verfestigung & Enthüllung (Bild 7-10) ---
5078+
5079+ // 4. Verfestigung: Den Weichzeichner auf 0 animieren
5080+ const solidificationAnimation = gooeyFilter.animate(
5081+ { stdDeviation: [15, 0] },
5082+ { duration: 300, easing: 'ease-out', fill: 'forwards' }
5083+ );
50855084
5086- // 4. Aufräumen: Filter entfernen, damit Buttons scharf werden
5085+ // 5. Enthüllung: Icons einblenden, während die Form fest wird
5086+ buttons.forEach((btn, index) => {
5087+ const icon = btn.querySelector('svg');
5088+ icon.animate(
5089+ { opacity: [0, 1], transform: ['scale(0.8)', 'scale(1)'] },
5090+ { duration: 300, delay: index * 30, easing: 'ease-out', fill: 'forwards' }
5091+ );
5092+ });
5093+
5094+ await solidificationAnimation.finished;
5095+
5096+ // 6. Aufräumen: Filter komplett entfernen, um die Performance zu schonen
50875097 categoryButtonsContainer.style.filter = 'none';
50885098 }
50895099
@@ -5100,37 +5110,53 @@ class FastSearchCard extends HTMLElement {
51005110 if (!this.isMenuView) return;
51015111
51025112 const buttons = Array.from(categoryButtonsContainer.querySelectorAll('.category-button'));
5113+ const gooeyFilter = this.shadowRoot.querySelector('#categoryGooey feGaussianBlur');
5114+
5115+ if (!gooeyFilter) {
5116+ // Fallback zur einfachen Animation
5117+ categoryButtonsContainer.classList.remove('visible');
5118+ this.isMenuView = false;
5119+ return;
5120+ }
51035121
5104- // Reverse Animation: Buttons zurück zum Startpunkt
5105- categoryButtonsContainer.style.filter = 'url(#categoryGooey)'; // Filter wieder aktivieren
5122+ // Reverse Spotlight Animation
5123+ categoryButtonsContainer.style.filter = 'url(#categoryGooey)';
5124+ gooeyFilter.setAttribute('stdDeviation', '15');
51065125
5107- const animations = buttons.map((btn, index) => {
5108- return btn.animate([
5109- { transform: `translateX(${index * (72 + 12)}px) scale(1)`, opacity: 1 },
5110- { transform: 'translateX(0px) scale(0)', opacity: 0 }
5111- ], {
5112- duration: 300,
5113- delay: (buttons.length - index - 1) * 50, // Rückwärts gestaffelt
5114- easing: 'ease-in',
5115- fill: 'forwards'
5116- });
5126+ // 1. Icons ausblenden
5127+ buttons.forEach((btn, index) => {
5128+ const icon = btn.querySelector('svg');
5129+ icon.animate(
5130+ { opacity: [1, 0], transform: ['scale(1)', 'scale(0.8)'] },
5131+ { duration: 200, delay: (buttons.length - index - 1) * 20, easing: 'ease-in', fill: 'forwards' }
5132+ );
51175133 });
51185134
5119- await Promise.all(animations.map(a => a.finished ));
5135+ await new Promise(resolve => setTimeout(resolve, 300 ));
51205136
5121- // Container zusammenziehen
5122- categoryButtonsContainer.animate([
5123- { width: `${buttons.length * 72 + (buttons.length - 1) * 12}px` },
5124- { width: '72px' }
5125- ], {
5126- duration: 200,
5127- easing: 'ease-in',
5128- fill: 'forwards'
5129- }).finished.then(() => {
5130- categoryButtonsContainer.classList.remove('visible');
5131- categoryButtonsContainer.style.filter = 'none';
5132- this.isMenuView = false;
5137+ // 2. Buttons zusammenziehen
5138+ const contractionAnimations = buttons.map((btn, index) => {
5139+ return btn.animate(
5140+ { transform: [`translateX(${index * (72 + 12)}px)`, 'translateX(0px)'] },
5141+ { duration: 400, delay: (buttons.length - index - 1) * 40, easing: 'ease-in', fill: 'forwards' }
5142+ );
51335143 });
5144+
5145+ await Promise.all(contractionAnimations.map(a => a.finished));
5146+
5147+ // 3. Container zusammenziehen
5148+ const containerWidth = buttons.length * 72 + (buttons.length - 1) * 12;
5149+ const containerAnimation = categoryButtonsContainer.animate(
5150+ { width: [`${containerWidth}px`, '72px'] },
5151+ { duration: 250, easing: 'ease-in', fill: 'forwards' }
5152+ );
5153+
5154+ await containerAnimation.finished;
5155+
5156+ // 4. Aufräumen
5157+ categoryButtonsContainer.classList.remove('visible');
5158+ categoryButtonsContainer.style.filter = 'none';
5159+ this.isMenuView = false;
51345160 }
51355161
51365162 handleCategorySelect(selectedButton) {
0 commit comments