PageSourceSearch

https://skillscout.sh/assets/site-shell.js?v=20260908-footer-offset-local

js skillscout.sh collected 2026-10-02 02:07:11 UTC 7,781 bytes, 217 lines download raw bytes

1(function () {
2  "use strict";
3
4  const DISMISS_KEY = "skillscout.mdviewerBannerDismissed";
5  const DISMISSED_CLASS = "mdviewer-banner-dismissed";
6  // Pageviews a returning visitor gets banner-free before the promo comes back.
7  const PAGEVIEWS_BEFORE_RESET = 10;
8  const scriptUrl = document.currentScript?.src;
9  const assetBaseUrl = scriptUrl ? new URL(".", scriptUrl) : new URL("/assets/", window.location.href);
10  const assetUrl = (fileName) => new URL(fileName, assetBaseUrl).href;
11
12  function readDismissal() {
13    let raw;
14    try {
15      raw = localStorage.getItem(DISMISS_KEY);
16    } catch {
17      return null;
18    }
19    if (!raw) return null;
20    // Legacy value: dismissal was permanent, so start its pageview count now.
21    if (raw === "1") return { views: 0 };
22    try {
23      const parsed = JSON.parse(raw);
24      if (parsed && typeof parsed === "object") {
25        return { views: Number(parsed.views) || 0 };
26      }
27    } catch {
28      // Unreadable value behaves like no dismissal at all.
29    }
30    return null;
31  }
32
33  function writeDismissal(views) {
34    try {
35      localStorage.setItem(DISMISS_KEY, JSON.stringify({ views }));
36    } catch {
37      // The banner still closes for this page when storage is unavailable.
38    }
39  }
40
41  function clearDismissal() {
42    try {
43      localStorage.removeItem(DISMISS_KEY);
44    } catch {
45      // Nothing to clean up when storage is unavailable.
46    }
47  }
48
49  function saveBannerDismissal() {
50    writeDismissal(0);
51  }
52
53  // Counts this pageview against the dismissal and reports whether the banner
54  // stays hidden. Runs once per page load, before the banner is rendered.
55  function isBannerDismissed() {
56    const dismissal = readDismissal();
57    if (!dismissal) return false;
58
59    const views = dismissal.views + 1;
60    if (views >= PAGEVIEWS_BEFORE_RESET) {
61      clearDismissal();
62      return false;
63    }
64
65    writeDismissal(views);
66    return true;
67  }
68
69  if (isBannerDismissed()) {
70    document.documentElement.classList.add(DISMISSED_CLASS);
71  }
72
73  function createMdviewerBanner() {
74    const banner = document.createElement("aside");
75    banner.className = "partner-banner";
76    banner.id = "mdviewerBanner";
77    banner.setAttribute("aria-label", "MDViewer promotion");
78    banner.innerHTML = `
79      <a
80        class="partner-banner-link"
81        href="https://getmd.ma/?utm_source=skillscout&utm_medium=referral&utm_campaign=mdviewer_banner&utm_content=banner"
82        target="_blank"
83        rel="noopener noreferrer"
84        aria-label="View any SKILL.md instantly with MDViewer"
85        data-telemetry-event="Partner.mdViewerOpened"
86        data-telemetry-placement="sitewide-partner-banner"
87      ></a>
88      <div class="partner-banner-inner">
89        <div class="partner-banner-brand" aria-hidden="true">
90          <img class="partner-banner-logo" src="${assetUrl("mdviewer-icon.webp")}" alt="" width="512" height="512" />
91          <span class="partner-banner-name">MDViewer</span>
92        </div>
93        <p class="partner-banner-copy" aria-hidden="true">
94          <svg class="partner-banner-copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
95            <path d="M2.5 12s3.5-5.5 9.5-5.5 9.5 5.5 9.5 5.5-3.5 5.5-9.5 5.5S2.5 12 2.5 12Z"></path>
96            <circle cx="12" cy="12" r="2.5"></circle>
97          </svg>
98          <span>View any <code>SKILL.md</code> instantly <span class="partner-banner-copy-suffix">with MDViewer</span></span>
99        </p>
100        <div class="partner-banner-actions">
101          <span class="partner-banner-cta" aria-hidden="true">Get MDViewer</span>
102          <button class="partner-banner-dismiss" id="dismissMdviewerBanner" type="button" aria-label="Dismiss MDViewer banner">
103            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
104              <path d="M6 6l12 12M18 6 6 18"></path>
105            </svg>
106          </button>
107        </div>
108      </div>
109    `;
110    return banner;
111  }
112
113  function ensureMdviewerBanner() {
114    let banner = document.getElementById("mdviewerBanner");
115    if (!banner) {
116      banner = createMdviewerBanner();
117      const header = document.querySelector(".site-nav-wrap, #navWrap, body > header");
118      if (header) {
119        header.insertAdjacentElement("afterend", banner);
120      } else {
121        document.body.prepend(banner);
122      }
123    }
124
125    const dismissButton = banner.querySelector("#dismissMdviewerBanner");
126    if (dismissButton && !dismissButton.dataset.siteShellBound) {
127      dismissButton.dataset.siteShellBound = "true";
128      dismissButton.addEventListener("click", (event) => {
129        event.preventDefault();
130        event.stopPropagation();
131        saveBannerDismissal();
132        document.documentElement.classList.add(DISMISSED_CLASS);
133        banner.hidden = true;
134      });
135    }
136  }
137
138  function bindArticleHeader() {
139    const burgerButton = document.getElementById("articleBurgerBtn");
140    const mobileMenu = document.getElementById("articleMobileMenu");
141    const navWrap = document.getElementById("articleNavWrap");
142
143    if (burgerButton && mobileMenu) {
144      burgerButton.addEventListener("click", () => {
145        const open = mobileMenu.classList.toggle("open");
146        burgerButton.classList.toggle("open", open);
147        burgerButton.setAttribute("aria-expanded", String(open));
148      });
149
150      mobileMenu.querySelectorAll(".site-mobile-link").forEach((link) => {
151        link.addEventListener("click", () => {
152          mobileMenu.classList.remove("open");
153          burgerButton.classList.remove("open");
154          burgerButton.setAttribute("aria-expanded", "false");
155        });
156      });
157    }
158
159    if (navWrap) {
160      const syncNavBorder = () => navWrap.classList.toggle("scrolled", window.scrollY > 8);
161      syncNavBorder();
162      window.addEventListener("scroll", syncNavBorder, { passive: true });
163    }
164  }
165
166  function ensureCoffeeButton() {
167    if (document.getElementById("buyMeACoffeeButton")) return;
168
169    const button = document.createElement("a");
170    button.className = "bmc-support-button";
171    button.id = "buyMeACoffeeButton";
172    button.href = "https://buymeacoffee.com/ulyanas";
173    button.target = "_blank";
174    button.rel = "noopener noreferrer";
175    button.setAttribute("aria-label", "Buy me a coffee");
176    button.setAttribute("data-telemetry-event", "Support.buyMeACoffeeOpened");
177    button.setAttribute("data-telemetry-placement", "sitewide-floating-button");
178    button.innerHTML = `
179      <img
180        class="bmc-support-logo"
181        src="${assetUrl("bmc-brand-logo.svg")}"
182        alt=""
183        width="195"
184        height="40"
185        aria-hidden="true"
186      />
187    `;
188    document.body.append(button);
189
190    const footer = document.querySelector("body > footer");
191    if (!footer) return;
192
193    let updateScheduled = false;
194    const updateFooterOffset = () => {
195      updateScheduled = false;
196      const footerRect = footer.getBoundingClientRect();
197      const visibleFooterHeight = Math.max(0, window.innerHeight - footerRect.top);
198      const footerOffset = Math.min(visibleFooterHeight, footerRect.height);
199      button.style.setProperty("--bmc-footer-offset", `${Math.ceil(footerOffset)}px`);
200    };
201    const scheduleFooterOffsetUpdate = () => {
202      if (updateScheduled) return;
203      updateScheduled = true;
204      window.requestAnimationFrame(updateFooterOffset);
205    };
206
207    updateFooterOffset();
208    window.addEventListener("scroll", scheduleFooterOffsetUpdate, { passive: true });
209    window.addEventListener("resize", scheduleFooterOffsetUpdate);
210  }
211
212  document.addEventListener("DOMContentLoaded", () => {
213    ensureMdviewerBanner();
214    bindArticleHeader();
215    ensureCoffeeButton();
216  });
217})();

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.