LabCodeHub öffentliche Ansicht
Anmelden
Küpper / Quildrop öffentlich
Branch: main
Quildrop / themes / ehc / static / js / partner-carousel.js
Verlauf Rohdaten
R Rüdiger Küpper fix: new version with themes + multi arch builds
b56ed7e0 vor 14 Tagen
themes/ehc/static/js/partner-carousel.js 112 Zeilen · 3.5 KB · JavaScript
1
/* ============================================================
2
   Partner-Carousel — Quilldrop Widget
3
   ------------------------------------------------------------
4
   Erwartet im DOM:
5
     <div id="partner-carousel"></div>
6
     <div id="partner-carousel-dots"></div>      (optional)
7
8
   Daten: /static/data/partners.json
9
   Konfig per data-Attribut auf #partner-carousel:
10
     data-visible="3"     Anzahl gleichzeitig sichtbarer Logos
11
     data-interval="3500" Auto-Rotation in ms
12
   ============================================================ */
13
(function() {
14
  'use strict';
15
16
  const DATA_URL = '/static/data/partners.json';
17
18
  function esc(s) {
19
    return String(s).replace(/[&<>"]/g, c =>
20
      ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c])
21
    );
22
  }
23
24
  function build(host, dotsBox, partners, opts) {
25
    const VISIBLE  = opts.visible;
26
    const INTERVAL = opts.interval;
27
28
    host.classList.add('carousel');
29
    host.innerHTML = '';
30
31
    const track = document.createElement('div');
32
    track.className = 'carousel-track';
33
    host.appendChild(track);
34
35
    // Slides + Klone für Endlos-Loop
36
    const all = partners.concat(partners.slice(0, VISIBLE));
37
    all.forEach(p => {
38
      const slide = document.createElement('div');
39
      slide.className = 'carousel-slide';
40
      const card = `<div class="partner-card" title="${esc(p.name)}">
41
        <img src="${esc(p.src)}" alt="${esc(p.name)}" loading="lazy" />
42
      </div>`;
43
      slide.innerHTML = p.url
44
        ? `<a href="${esc(p.url)}" target="_blank" rel="noopener" class="partner-link" aria-label="${esc(p.name)}">${card}</a>`
45
        : card;
46
      track.appendChild(slide);
47
    });
48
49
    // Dots
50
    if (dotsBox) {
51
      dotsBox.innerHTML = '';
52
      partners.forEach((_, i) => {
53
        const b = document.createElement('button');
54
        b.className = 'carousel-dot' + (i === 0 ? ' active' : '');
55
        b.setAttribute('aria-label', `Partner ${i + 1}`);
56
        b.addEventListener('click', () => goTo(i));
57
        dotsBox.appendChild(b);
58
      });
59
    }
60
61
    let index = 0;
62
    function update() {
63
      track.style.transition = 'transform 0.7s cubic-bezier(0.4, 0, 0.2, 1)';
64
      track.style.transform  = `translateX(-${(100 / VISIBLE) * index}%)`;
65
      if (dotsBox) {
66
        const active = index % partners.length;
67
        [...dotsBox.children].forEach((d, i) => d.classList.toggle('active', i === active));
68
      }
69
    }
70
    function goTo(i) { index = i; update(); }
71
    function next() {
72
      index++;
73
      update();
74
      if (index >= partners.length) {
75
        setTimeout(() => {
76
          track.style.transition = 'none';
77
          index = 0;
78
          track.style.transform = 'translateX(0)';
79
          if (dotsBox) [...dotsBox.children].forEach((d, i) => d.classList.toggle('active', i === 0));
80
        }, 720);
81
      }
82
    }
83
84
    update();
85
    setInterval(next, INTERVAL);
86
  }
87
88
  function init() {
89
    const host = document.getElementById('partner-carousel');
90
    if (!host) return;
91
    const dotsBox = document.getElementById('partner-carousel-dots');
92
93
    const opts = {
94
      visible:  parseInt(host.dataset.visible,  10) || 3,
95
      interval: parseInt(host.dataset.interval, 10) || 3500
96
    };
97
98
    fetch(DATA_URL)
99
      .then(r => r.json())
100
      .then(partners => {
101
        if (!Array.isArray(partners) || partners.length === 0) return;
102
        build(host, dotsBox, partners, opts);
103
      })
104
      .catch(err => console.error('partner-carousel:', err));
105
  }
106
107
  if (document.readyState === 'loading') {
108
    document.addEventListener('DOMContentLoaded', init);
109
  } else {
110
    init();
111
  }
112
})();