@@ -4215,6 +4215,7 @@ class FastSearchCard extends HTMLElement {
42154215 .timer-timeline-event {
42164216 cursor: pointer;
42174217 transition: all 0.2s ease;
4218+ position: relative;
42184219 }
42194220
42204221 .timer-timeline-event:hover {
@@ -9825,129 +9826,130 @@ class FastSearchCard extends HTMLElement {
98259826
98269827
98279828
9828- renderActiveTimers(timers, entityId) {
9829- const container = this.shadowRoot.getElementById(`active-timers-${entityId}`);
9830- if (!container) return;
9831-
9832- if (!timers || timers.length === 0) {
9833- container.innerHTML = '<div class="no-timers">Keine aktiven Timer</div>';
9834- return;
9835- }
9836-
9837- // Timer nach nächster Ausführung sortieren
9838- const sortedTimers = timers.sort((a, b) => {
9839- const nextA = this.getNextExecution(a);
9840- const nextB = this.getNextExecution(b);
9841- return nextA - nextB;
9842- });
9843-
9844-
98459829
9846-
9847- const timerHTML = sortedTimers.map(timer => {
9848- const nextExecution = this.getNextExecution(timer);
9849- const timeUntil = this.formatTimeUntil(nextExecution);
9850- const action = this.getTimerAction(timer);
9830+ renderActiveTimers(timers, entityId) {
9831+ const container = this.shadowRoot.getElementById(`active-timers-${entityId}`);
9832+ if (!container) return;
98519833
9852-
9853- // Timer Icon basierend auf Action
9854- const timerIcon = this.getTimerIconForAction(action) ;
9855-
9834+ if (!timers || timers.length === 0) {
9835+ container.innerHTML = '<div class="no-timers">Keine aktiven Timer</div>';
9836+ return ;
9837+ }
98569838
9857- return `
9858- <div class="timeline-event timer-timeline-event" data-timer-id="${timer.schedule_id}">
9859- <div class="timeline-event-icon">
9860- ${timerIcon}
9861- </div>
9862- <div class="timeline-event-content">
9863- <div class="timeline-event-title">
9864- ${timer.name}
9839+ // Timer nach nächster Ausführung sortieren
9840+ const sortedTimers = timers.sort((a, b) => {
9841+ const nextA = this.getNextExecution(a);
9842+ const nextB = this.getNextExecution(b);
9843+ return nextA - nextB;
9844+ });
9845+
9846+ const timerHTML = sortedTimers.map(timer => {
9847+ const nextExecution = this.getNextExecution(timer);
9848+ const timeUntil = this.formatTimeUntil(nextExecution);
9849+ const action = this.getTimerAction(timer);
9850+
9851+ // Timer Icon basierend auf Action
9852+ const timerIcon = this.getTimerIconForAction(action);
9853+
9854+ return `
9855+ <div class="timeline-event timer-timeline-event" data-timer-id="${timer.schedule_id}">
9856+ <div class="timeline-event-icon">
9857+ ${timerIcon}
98659858 </div>
9866- <div class="timeline-event-details">
9867- <span class="timer-type-badge">${action}</span>
9868- <span class="timer-time-badge">${timeUntil}</span>
9859+ <div class="timeline-event-content">
9860+ <div class="timeline-event-title">
9861+ ${timer.name}
9862+ </div>
9863+ <div class="timeline-event-details">
9864+ <span class="timer-type-badge">${action}</span>
9865+ <span class="timer-time-badge">${timeUntil}</span>
9866+ </div>
9867+ </div>
9868+ <div class="timeline-event-time">
9869+ <button class="timer-edit" data-timer-id="${timer.schedule_id}" title="Timer bearbeiten">
9870+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
9871+ <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
9872+ <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
9873+ </svg>
9874+ </button>
9875+
9876+ <button class="timer-delete" data-timer-id="${timer.schedule_id}" title="Timer löschen">
9877+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
9878+ <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
9879+ <path d="M4 7l16 0" />
9880+ <path d="M10 11l0 6" />
9881+ <path d="M14 11l0 6" />
9882+ <path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
9883+ <path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
9884+ </svg>
9885+ </button>
98699886 </div>
98709887 </div>
9871- <div class="timeline-event-time">
9872- <button class="timer-edit" data-timer-id="${timer.schedule_id}" title="Timer bearbeiten">
9873- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
9874- <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2-2v-7"></path>
9875- <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
9876- </svg>
9877- </button>
9878-
9879- <button class="timer-delete" data-timer-id="${timer.schedule_id}" title="Timer löschen">
9880- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
9881- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
9882- <path d="M4 7l16 0" />
9883- <path d="M10 11l0 6" />
9884- <path d="M14 11l0 6" />
9885- <path d="M5 7l1 12a2 2 0 0 0 2 -2l1 -12" />
9886- <path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
9887- </svg>
9888- </button>
9889- </div>
9888+ `;
9889+ }).join('');
9890+
9891+ container.innerHTML = `
9892+ <div class="active-timers-grid">
9893+ ${timerHTML}
98909894 </div>
98919895 `;
9892- }).join('');
9893-
9894-
9895-
9896-
9897- container.innerHTML = `
9898- <div class="active-timers-grid">
9899- ${timerHTML}
9900- </div>
9901- `;
9902-
9903- // Event Listeners für Edit Buttons
9904- container.querySelectorAll('.timer-edit').forEach(btn => {
9905- btn.addEventListener('click', () => {
9906- const timerId = btn.dataset.timerId;
9907- this.handleEditTimerClick(timerId, entityId);
9908- });
9909- });
9910-
9911- // Event Listeners für Delete Buttons
9912- container.querySelectorAll('.timer-delete').forEach(btn => {
9913- btn.addEventListener('click', () => {
9914- const timerId = btn.dataset.timerId;
9915- this.deleteTimer(timerId, entityId);
9916- });
9917- });
9918-
9919- // Entrance-Animationen mit Web Animations API (wie bei Actions)
9920- const timerItems = container.querySelectorAll('.timer-timeline-event');
9921- timerItems.forEach((item, index) => {
9922- // Initial state
9923- item.style.opacity = '0';
9924- item.style.transform = 'translateY(20px)';
99259896
9926- // Animate in mit gestaffeltem Delay
9927- setTimeout(() => {
9928- item.animate([
9929- { opacity: 0, transform: 'translateY(20px)' },
9930- { opacity: 1, transform: 'translateY(0)' }
9931- ], {
9932- duration: 300,
9933- delay: index * 50,
9934- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
9935- fill: 'forwards'
9897+ // Event Listeners für Edit Buttons
9898+ container.querySelectorAll('.timer-edit').forEach(btn => {
9899+ btn.addEventListener('click', () => {
9900+ const timerId = btn.dataset.timerId;
9901+ this.handleEditTimerClick(timerId, entityId);
99369902 });
9937- }, 50);
9938- });
9939-
9940- }
9941-
9903+ });
9904+
9905+ // Event Listeners für Delete Buttons
9906+ container.querySelectorAll('.timer-delete').forEach(btn => {
9907+ btn.addEventListener('click', () => {
9908+ const timerId = btn.dataset.timerId;
9909+ this.deleteTimer(timerId, entityId);
9910+ });
9911+ });
9912+
9913+ // Entrance-Animationen mit Web Animations API (wie bei Actions)
9914+ const timerItems = container.querySelectorAll('.timer-timeline-event');
9915+ timerItems.forEach((item, index) => {
9916+ // Initial state
9917+ item.style.opacity = '0';
9918+ item.style.transform = 'translateY(20px)';
9919+
9920+ // Animate in mit gestaffeltem Delay
9921+ setTimeout(() => {
9922+ item.animate([
9923+ { opacity: 0, transform: 'translateY(20px)' },
9924+ { opacity: 1, transform: 'translateY(0)' }
9925+ ], {
9926+ duration: 300,
9927+ delay: index * 50,
9928+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
9929+ fill: 'forwards'
9930+ });
9931+ }, 50);
9932+ });
9933+ }
99429934
99439935 getTimerIconForAction(action) {
9944- // Bestimme Icon basierend auf Action-Text
9936+ // Timer Icon basierend auf Action
99459937 if (action.includes('Einschalten') || action.includes('Ein')) {
9946- return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 12l2 2 4-4"></path>< circle cx="12" cy="12" r="9"></circle></svg>`;
9938+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"></circle><path d="M9 12l2 2 4-4"></path ></svg>`;
99479939 } else if (action.includes('Ausschalten') || action.includes('Aus')) {
9948- return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="18 " y1="6 " x2="6 " y2="18 "></line><line x1="6 " y1="6 " x2="18 " y2="18 "></line></svg>`;
9949- } else if (action.includes('30% ') || action.includes('Dimmen ')) {
9940+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"></circle>< line x1="15 " y1="9 " x2="9 " y2="15 "></line><line x1="9 " y1="9 " x2="15 " y2="15 "></line></svg>`;
9941+ } else if (action.includes('Dimmen ') || action.includes('% ')) {
99509942 return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line></svg>`;
9943+ } else if (action.includes('Heizen') || action.includes('°C')) {
9944+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z"></path></svg>`;
9945+ } else if (action.includes('Kühlen')) {
9946+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12h20M12 2v20m8-8-8-8-8 8m16 0-8 8-8-8"></path></svg>`;
9947+ } else if (action.includes('Öffnen') || action.includes('Schließen')) {
9948+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M7 2h10l5 5v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z"></path><path d="M8 6h8v4H8V6z"></path></svg>`;
9949+ } else if (action.includes('Abspielen') || action.includes('Play')) {
9950+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><polygon points="5,3 19,12 5,21"></polygon></svg>`;
9951+ } else if (action.includes('Pausieren') || action.includes('Pause')) {
9952+ return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>`;
99519953 } else {
99529954 // Fallback: generisches Timer-Icon
99539955 return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"></circle><polyline points="12,6 12,12 16,14"></polyline></svg>`;
0 commit comments