@@ -164,10 +164,9 @@ import { UI } from 'astrowind:config';
164164<script is:inline >
165165 /* Inspired by: https://github.com/heidkaemper/tailwindcss-intersect */
166166 const Observer = {
167- observers: {},
168- visibleElementsQueue: [],
169- processing: false,
167+ observer: null,
170168 delayBetweenAnimations: 100,
169+ animationCounter: 0,
171170
172171 start() {
173172 const selectors = [
@@ -182,100 +181,75 @@ import { UI } from 'astrowind:config';
182181
183182 const elements = Array.from(document.querySelectorAll(selectors.join(',')));
184183
185- elements.forEach((el) => el.setAttribute('no-intersect', ''));
186-
187184 const getThreshold = (element) => {
188185 if (element.classList.contains('intersect-full')) return 0.99;
189186 if (element.classList.contains('intersect-half')) return 0.5;
190187 if (element.classList.contains('intersect-quarter')) return 0.25;
191188 return 0;
192189 };
193190
194- Object.values(this.observers).forEach((observer) => observer.disconnect());
195- this.observers = {};
191+ elements.forEach((el) => {
192+ el.setAttribute('no-intersect', '');
193+ el._intersectionThreshold = getThreshold(el);
194+ });
196195
197196 const callback = (entries) => {
198197 entries.forEach((entry) => {
199- const target = entry.target;
200-
201- if (entry.isIntersecting) {
202- if (target.classList.contains('intercept-no-queue')) {
203- target.removeAttribute('no-intersect');
204- if (target.classList.contains('intersect-once')) {
205- Object.values(this.observers).forEach((observer) => observer.unobserve(target));
198+ requestAnimationFrame(() => {
199+ const target = entry.target;
200+ const intersectionRatio = entry.intersectionRatio;
201+ const threshold = target._intersectionThreshold;
202+
203+ if (target.classList.contains('intersect-no-queue')) {
204+ if (entry.isIntersecting) {
205+ target.removeAttribute('no-intersect');
206+ if (target.classList.contains('intersect-once')) {
207+ this.observer.unobserve(target);
208+ }
209+ } else {
210+ target.setAttribute('no-intersect', '');
206211 }
207212 return;
208213 }
209214
210- if (!this.visibleElementsQueue.includes(target)) {
211- this.visibleElementsQueue.push(target);
212- }
215+ if (intersectionRatio >= threshold) {
216+ if (!target.hasAttribute('data-animated')) {
217+ target.removeAttribute('no-intersect');
218+ target.setAttribute('data-animated', 'true');
219+
220+ const delay = this.animationCounter * this.delayBetweenAnimations;
221+ this.animationCounter++;
222+
223+ target.style.transitionDelay = `${delay}ms`;
224+ target.style.animationDelay = `${delay}ms`;
213225
214- this.processQueue();
215- } else {
216- target.setAttribute('no-intersect', '');
226+ if (target.classList.contains('intersect-once')) {
227+ this.observer.unobserve(target);
228+ }
229+ }
230+ } else {
231+ target.setAttribute('no-intersect', '');
232+ target.removeAttribute('data-animated');
233+ target.style.transitionDelay = '';
234+ target.style.animationDelay = '';
217235
218- const index = this.visibleElementsQueue.indexOf(target);
219- if (index > -1) {
220- this.visibleElementsQueue.splice(index, 1);
236+ this.animationCounter = 0;
221237 }
222- }
238+ });
223239 });
224240 };
225241
226- elements.forEach((el) => {
227- const threshold = getThreshold(el);
228-
229- if (!this.observers[threshold]) {
230- this.observers[threshold] = new IntersectionObserver(callback, { threshold });
231- }
242+ this.observer = new IntersectionObserver(callback.bind(this), { threshold: [0, 0.25, 0.5, 0.99] });
232243
233- this.observers[threshold].observe(el);
244+ elements.forEach((el) => {
245+ this.observer.observe(el);
234246 });
235247 },
236-
237- async processQueue() {
238- if (this.processing) {
239- return;
240- }
241-
242- this.processing = true;
243-
244- while (this.visibleElementsQueue.length > 0) {
245- const element = this.visibleElementsQueue.shift();
246-
247- element.removeAttribute('no-intersect');
248-
249- if (element.classList.contains('intersect-once')) {
250- Object.values(this.observers).forEach((observer) => observer.unobserve(element));
251- }
252-
253- if (this.isElementInViewport(element)) {
254- await this.delay(this.delayBetweenAnimations);
255- }
256- }
257-
258- this.processing = false;
259- },
260-
261- delay(ms) {
262- return new Promise((resolve) => setTimeout(resolve, ms));
263- },
264-
265- isElementInViewport(element) {
266- const rect = element.getBoundingClientRect();
267- return (
268- rect.top < (window.innerHeight || document.documentElement.clientHeight) &&
269- rect.bottom > 0 &&
270- rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
271- rect.right > 0
272- );
273- },
274248 };
275249
276250 Observer.start();
277251
278252 document.addEventListener('astro:after-swap', () => {
279253 Observer.start();
280254 });
281- </script >
255+ </script >
0 commit comments