PageSourceSearch

https://www.trysalute.com/js/transformation.js

js trysalute.com collected 2026-09-24 14:55:08 UTC 3,837 bytes, 147 lines download raw bytes

1const transformationTiles = document.querySelectorAll('.transformation-card');
2const transformationDots = document.querySelectorAll('.transformation-dot');
3const carouselTrack = document.querySelector('.carousel-track');
4let currentIndex = 0;
5let autoPlayInterval;
6let isHovering = false;
7
8/* ─── Helper: detect mobile ─── */
9function isMobile() {
10  return window.matchMedia('(max-width: 768px)').matches;
11}
12
13/* ─── Desktop: fade-based carousel ─── */
14function showTile(index) {
15  transformationTiles.forEach((tile, i) => {
16    tile.classList.remove('active');
17    if (i === index) tile.classList.add('active');
18  });
19
20  transformationDots.forEach((dot, i) => {
21    dot.classList.remove('active');
22    if (i === index) dot.classList.add('active');
23  });
24
25  currentIndex = index;
26}
27
28function nextTile() {
29  const next = (currentIndex + 1) % transformationTiles.length;
30  showTile(next);
31}
32
33function startAutoPlay() {
34  autoPlayInterval = setInterval(() => {
35    if (!isHovering) nextTile();
36  }, 5000);
37}
38
39function stopAutoPlay() {
40  clearInterval(autoPlayInterval);
41}
42
43/* ─── Mobile: scroll-based carousel ─── */
44function syncDotsToScroll() {
45  if (!isMobile()) return;
46
47  const trackRect = carouselTrack.getBoundingClientRect();
48  let closestIndex = 0;
49  let closestDist = Infinity;
50
51  transformationTiles.forEach((tile, i) => {
52    const tileRect = tile.getBoundingClientRect();
53    const tileCenter = tileRect.left + tileRect.width / 2;
54    const trackCenter = trackRect.left + trackRect.width / 2;
55    const dist = Math.abs(tileCenter - trackCenter);
56    if (dist < closestDist) {
57      closestDist = dist;
58      closestIndex = i;
59    }
60  });
61
62  transformationDots.forEach((dot, i) => {
63    dot.classList.toggle('active', i === closestIndex);
64  });
65
66  currentIndex = closestIndex;
67}
68
69function scrollToTile(index) {
70  if (!isMobile()) return;
71  transformationTiles[index].scrollIntoView({
72    behavior: 'smooth',
73    block: 'nearest',
74    inline: 'center',
75  });
76}
77
78/* ─── Dot click ─── */
79transformationDots.forEach((dot, index) => {
80  dot.addEventListener('click', () => {
81    if (isMobile()) {
82      scrollToTile(index);
83    } else {
84      stopAutoPlay();
85      showTile(index);
86      startAutoPlay();
87    }
88  });
89});
90
91/* ─── Desktop tile hover / click ─── */
92transformationTiles.forEach(tile => {
93  tile.addEventListener('mouseenter', () => {
94    if (isMobile()) return;
95    isHovering = true;
96    tile.classList.add('clickable');
97  });
98
99  tile.addEventListener('mouseleave', () => {
100    if (isMobile()) return;
101    isHovering = false;
102    tile.classList.remove('clickable');
103  });
104
105  tile.addEventListener('click', () => {
106    if (!isMobile() && tile.classList.contains('active')) {
107      console.log('Tile clicked:', tile.querySelector('h2').textContent);
108      alert('Tile clicked: ' + tile.querySelector('h2').textContent);
109    }
110  });
111});
112
113/* ─── Mobile: sync dots on scroll ─── */
114carouselTrack.addEventListener('scroll', syncDotsToScroll, { passive: true });
115
116/* ─── Init ─── */
117function init() {
118  if (isMobile()) {
119    stopAutoPlay();
120    // Ensure all cards are visible (CSS handles this, but reset any JS state)
121    transformationTiles.forEach(tile => tile.classList.remove('active'));
122    syncDotsToScroll();
123  } else {
124    showTile(0);
125    startAutoPlay();
126  }
127}
128
129/* ─── Re-init on resize crossing the breakpoint ─── */
130let wasMobile = isMobile();
131window.addEventListener('resize', () => {
132  const nowMobile = isMobile();
133  if (nowMobile !== wasMobile) {
134    wasMobile = nowMobile;
135    stopAutoPlay();
136    init();
137  }
138});
139
140/* ─── Page visibility ─── */
141document.addEventListener('visibilitychange', () => {
142  if (isMobile()) return;
143  if (document.hidden) stopAutoPlay();
144  else startAutoPlay();
145});
146
147init();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.