PageSourceSearch

https://nebios.org/js/lib/feature-showcase.js

js nebios.org collected 2026-10-06 10:18:28 UTC 5,460 bytes, 185 lines download raw bytes

1/**
2 * feature-showcase.js
3 *
4 * Desktop (≥1360px): scroll pozisyonuna göre slayt değişir
5 * Mobil (<1360px): touch swipe ile slayt değişir
6 *
7 * Geçiş: crossfade — out ve in aynı anda, translateY şiddetli
8 *
9 * Slayt sayısı DOM'dan okunur. Slayt eklerken/çıkarırken burada
10 * değiştirilecek bir şey yok, sadece .feature-showcase yüksekliği
11 * slayt sayısıyla uyumlu olmalı.
12 */
13(function () {
14  function init() {
15    const showcase = document.querySelector(".feature-showcase");
16    if (!showcase) return;
17
18    const slides = showcase.querySelectorAll(".feature-slide");
19    const dots = showcase.querySelectorAll(".feature-dot");
20    const scrollEl = document.querySelector(".fullcontent");
21    if (!scrollEl || !slides.length) return;
22
23    const TOTAL = slides.length;
24
25    // Nokta sayısı slayt sayısını tutmuyorsa fazlalıkları gizle
26    dots.forEach((dot, i) => {
27      dot.style.display = i < TOTAL ? "" : "none";
28    });
29
30    // Kaydırma alanı slayt sayısına göre ayarlanır, CSS'te sabit
31    // yükseklik tutmaya gerek kalmaz
32    showcase.style.height = TOTAL * 100 + "vh";
33
34    const isMobile = () => window.innerWidth < 1360;
35
36    let current = 0;
37    let animating = false;
38    let pending = null;
39
40    function goTo(next, dir) {
41      if (next < 0 || next >= TOTAL || next === current) return;
42
43      // Animasyon sürerken gelen istek kaybolmasın, sonunda uygulanır
44      if (animating) {
45        pending = next;
46        return;
47      }
48      animating = true;
49
50      const outSlide = slides[current];
51      const inSlide = slides[next];
52      const outY = dir > 0 ? "-64px" : "64px";
53      const inY = dir > 0 ? "64px" : "-64px";
54
55      // In slide hazırla — görünmez, offset pozisyonda
56      inSlide.style.cssText =
57        "opacity: 0; display: flex;" +
58        " transform: translateY(" +
59        inY +
60        ") scale(0.9);" +
61        " filter: blur(var(--wtk-translucent-blur));";
62      inSlide.classList.add("active");
63
64      // Her ikisi de transition başlat (crossfade)
65      requestAnimationFrame(() => {
66        requestAnimationFrame(() => {
67          const transition =
68            "opacity 350ms ease, transform 350ms ease, filter 350ms ease";
69
70          outSlide.style.transition = transition;
71          outSlide.style.opacity = "0";
72          outSlide.style.transform = `translateY(${outY}) scale(0.9)`;
73          outSlide.style.filter = "blur(var(--wtk-translucent-blur))";
74
75          inSlide.style.transition = transition;
76          inSlide.style.opacity = "1";
77          inSlide.style.transform = "translateY(0) scale(1)";
78          inSlide.style.filter = "blur(0px)";
79
80          setTimeout(() => {
81            outSlide.classList.remove("active");
82            outSlide.style.cssText = "";
83            inSlide.style.cssText = "";
84            animating = false;
85
86            if (pending !== null) {
87              const target = pending;
88              pending = null;
89              goTo(target, target > current ? 1 : -1);
90            }
91          }, 360);
92        });
93      });
94
95      if (dots.length) {
96        if (dots[current]) dots[current].classList.remove("active");
97        if (dots[next]) dots[next].classList.add("active");
98      }
99
100      current = next;
101    }
102
103    // ─── Desktop: scroll pozisyonuna göre slayt ───
104    function onScroll() {
105      const showcaseTop = showcase.offsetTop;
106      const scrollY = scrollEl.scrollTop;
107      const relativeScroll = scrollY - showcaseTop;
108      const slideHeight = window.innerHeight;
109
110      if (relativeScroll < 0 || relativeScroll > slideHeight * TOTAL) return;
111
112      const newIndex = Math.min(
113        TOTAL - 1,
114        Math.max(
115          0,
116          Math.floor((relativeScroll + slideHeight * 0.5) / slideHeight),
117        ),
118      );
119      if (newIndex !== current) {
120        goTo(newIndex, newIndex > current ? 1 : -1);
121      }
122    }
123
124    scrollEl.addEventListener("scroll", onScroll, { passive: true });
125
126    // Dot tıklaması → scroll pozisyonunu ayarla
127    dots.forEach((dot, i) => {
128      if (i >= TOTAL) return;
129      dot.addEventListener("click", () => {
130        const showcaseTop = showcase.offsetTop;
131        scrollEl.scrollTo({
132          top: showcaseTop + i * window.innerHeight,
133        });
134      });
135    });
136
137    // ─── Mobil: touch swipe ───
138    let touchStartY = 0;
139    let touchStartX = 0;
140    let swiping = false;
141
142    showcase.addEventListener(
143      "touchstart",
144      (e) => {
145        touchStartY = e.touches[0].clientY;
146        touchStartX = e.touches[0].clientX;
147        swiping = true;
148      },
149      { passive: true },
150    );
151
152    showcase.addEventListener(
153      "touchend",
154      (e) => {
155        if (!swiping || !isMobile()) return;
156        swiping = false;
157
158        const deltaY = touchStartY - e.changedTouches[0].clientY;
159        const deltaX = touchStartX - e.changedTouches[0].clientX;
160
161        if (Math.abs(deltaX) > Math.abs(deltaY)) return;
162        if (Math.abs(deltaY) < 60) return;
163
164        const dir = deltaY > 0 ? 1 : -1;
165        const next = current + dir;
166
167        if (next < 0 || next >= TOTAL) return;
168
169        const showcaseTop = showcase.offsetTop;
170        scrollEl.scrollTo({
171          top: showcaseTop + next * window.innerHeight,
172        });
173
174        goTo(next, dir);
175      },
176      { passive: true },
177    );
178  }
179
180  if (document.readyState === "loading") {
181    document.addEventListener("DOMContentLoaded", init);
182  } else {
183    init();
184  }
185})();

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.