PageSourceSearch

https://www.marigold.cz/js/promo-banner.js

js marigold.cz collected 2026-10-02 10:16:10 UTC 5,281 bytes, 114 lines download raw bytes

1/*
2 * Dynamický banner aktuální akce / workshopu.
3 * Zdroj pravdy pro inzerci napříč webem — čte živá data z vibecoding.cz API.
4 *
5 * Použití: vlož kontejner s id="vibecoding-promo" a data-atributy,
6 * pak načti tento skript:
7 *
8 *   <div class="posts">
9 *     <div id="vibecoding-promo" data-utm-campaign="event-promo" style="display:none;"></div>
10 *   </div>
11 *   <script src="/js/promo-banner.js" defer></script>
12 *
13 * data-utm-campaign — hodnota utm_campaign v odkazu (default: "event-promo")
14 */
15(function () {
16  var container = document.getElementById('vibecoding-promo');
17  if (!container) return;
18
19  var campaign = container.getAttribute('data-utm-campaign') || 'event-promo';
20  // Plocha pro promo analytiku (homepage | article | other). Banner bývá v postech → 'article'.
21  var surface = container.getAttribute('data-surface') || 'article';
22  var months = ['ledna', 'února', 'března', 'dubna', 'května', 'června',
23    'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'];
24
25  fetch('https://www.vibecoding.cz/api/active-promotion')
26    .then(function (r) { return r.json(); })
27    .then(function (e) {
28      if (!e || !e.slug) return;
29
30      // Data z API se vkládají do innerHTML — escapuj vše interpolované.
31      function esc(s) {
32        return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
33          return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
34        });
35      }
36
37      // Reklama / externí promo slot (isAd): nemá reálný termín ani město,
38      // místo „Naše akce" má vlastní štítek a CTA „Více". Datum se nezobrazuje.
39      var isAd = !!e.isAd;
40
41      var dateText = '';
42      if (!isAd && e.date) {
43        var d = e.date.split('-');
44        var df = parseInt(d[2]) + '. ' + months[parseInt(d[1]) - 1] + ' ' + d[0];
45        var city = e.city || (e.location ? e.location.split(',').slice(-1)[0].trim() : '');
46        dateText = df + (city ? ' · ' + city : '') +
47          (e.dateVariants && e.dateVariants.length > 1 ? ' · a další termíny' : '');
48      }
49      // Klik vede přes náš promo redirect (změří klik podle site/surface + připojí UTM).
50      // clickUrl nemá query string → parametry přidáváme přes URL API, ne lepením '&'.
51      // Fallback na přímý odkaz na akci, kdyby clickUrl chybělo (starší cache odpovědi).
52      var url;
53      if (e.clickUrl) {
54        try {
55          var cu = new URL(e.clickUrl);
56          cu.searchParams.set('site', 'marigold');
57          cu.searchParams.set('surface', surface);
58          url = cu.toString();
59        } catch (_) { url = e.clickUrl; }
60      } else {
61        url = 'https://www.vibecoding.cz/akce/' + encodeURIComponent(e.slug).replace(/%2F/gi, '/') +
62          '/?utm_source=marigold&utm_medium=web&utm_campaign=' + encodeURIComponent(campaign);
63      }
64
65      if (e.isPaid) {
66        // Tmavý workshop banner
67        var earlyHtml = '';
68        if (e.earlyBirdPrice && e.earlyBirdDeadline) {
69          var now = new Date();
70          var deadline = new Date(e.earlyBirdDeadline + 'T23:59:59');
71          if (now <= deadline) {
72            var ed = e.earlyBirdDeadline.split('-');
73            earlyHtml = '<div class="workshop-banner-early">Early bird — do ' +
74              parseInt(ed[2]) + '. ' + months[parseInt(ed[1]) - 1] + '.</div>';
75          }
76        }
77        container.innerHTML =
78          '<a href="' + url + '" class="workshop-banner-link">' +
79            '<div class="workshop-banner">' +
80              '<div class="workshop-banner-content">' +
81                '<div class="workshop-banner-header-row">' +
82                  '<span class="workshop-banner-badge">' + (e.isPaid ? 'Workshop' : 'Akce') + '</span>' +
83                  '<span class="workshop-banner-date">' + esc(dateText) + '</span>' +
84                '</div>' +
85                '<div class="workshop-banner-title">' + esc(e.title) + '</div>' +
86                (e.bannerDescription ? '<div class="workshop-banner-desc">' + esc(e.bannerDescription) + '</div>' : '') +
87                earlyHtml +
88              '</div>' +
89              '<div class="workshop-banner-cta">' +
90                '<span class="workshop-banner-btn">Detaily &rarr;</span>' +
91              '</div>' +
92            '</div>' +
93          '</a>';
94      } else {
95        // Kompaktní "Naše akce" banner
96        container.innerHTML =
97          '<a href="' + url + '" class="promo-card-compact-link">' +
98            '<div class="promo-card-compact">' +
99              '<div class="promo-left">' +
100                '<span class="promo-badge-sm">' + (isAd ? esc(e.badgeLabel || 'Tip') : 'Naše akce') + '</span>' +
101                '<span class="promo-title-sm">' + esc(e.title) + '</span>' +
102                (dateText ? '<span class="promo-meta">' + esc(dateText) + '</span>' : '') +
103                (e.bannerDescription ? '<span class="promo-meta">' + esc(e.bannerDescription) + '</span>' : '') +
104              '</div>' +
105              '<div class="promo-right">' +
106                '<span class="promo-cta-btn">' + (isAd ? 'Více' : 'Detaily') + ' &rarr;</span>' +
107              '</div>' +
108            '</div>' +
109          '</a>';
110      }
111      container.style.display = '';
112    })
113    .catch(function () {});
114})();

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.