PageSourceSearch

https://youtubehider.com/assets/js/support-modal.js

js youtubehider.com collected 2026-10-02 01:50:54 UTC 10,645 bytes, 246 lines download raw bytes

1(function () {
2  const KOFI_LINK = "https://ko-fi.com/D5Y424F3EB";
3  const GITHUB_LINK = "https://github.com/MatteoLucerni/youtube-hider-extension";
4  const REVIEW_LINK =
5    "https://chromewebstore.google.com/detail/ebpikpmmnpjmlcpanakfcgchkdjaanmm/reviews";
6
7  const css = `
8    .yh-support-trigger {
9      display: inline-flex; align-items: center; gap: 8px;
10      background: rgba(138, 180, 248, 0.14); color: #8ab4f8;
11      border: 1px solid rgba(138, 180, 248, 0.28); border-radius: 8px;
12      padding: 8px 16px; font-weight: 600; font-family: inherit; font-size: inherit;
13      text-decoration: none; cursor: pointer;
14      transition: background .2s cubic-bezier(.4,0,.2,1), border-color .2s cubic-bezier(.4,0,.2,1), transform .2s cubic-bezier(.4,0,.2,1);
15    }
16    .yh-support-trigger:hover {
17      background: rgba(138, 180, 248, 0.22); border-color: rgba(138, 180, 248, 0.5);
18      color: #8ab4f8; transform: translateY(-2px);
19    }
20    .yh-support-trigger:focus-visible { outline: 2px solid #8ab4f8; outline-offset: 2px; }
21
22    .yh-support-modal {
23      position: fixed; inset: 0; z-index: 100000; display: flex;
24      align-items: center; justify-content: center; padding: 24px;
25      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
26    }
27    .yh-support-modal[hidden] { display: none; }
28
29    .yh-support-scrim {
30      position: absolute; inset: 0; background: rgba(0, 0, 0, 0.7);
31      backdrop-filter: blur(3px); animation: yhSupportFade .16s cubic-bezier(.4,0,.2,1);
32    }
33
34    .yh-support-card {
35      position: relative; width: 100%; max-width: 420px; max-height: 100%;
36      overflow-y: auto; overscroll-behavior: contain; padding: 28px;
37      background:
38        radial-gradient(600px 300px at 20% -10%, rgba(138, 180, 248, 0.10), transparent 70%),
39        #242424;
40      border: 1px solid #3a3a3a; border-radius: 8px;
41      box-shadow: 0 0 0 1px rgba(255,255,255,.05), 0 2px 8px rgba(0,0,0,.25), 0 24px 60px rgba(0,0,0,.5);
42      animation: yhSupportIn .18s cubic-bezier(.4,0,.2,1);
43    }
44
45    @keyframes yhSupportFade { from { opacity: 0; } to { opacity: 1; } }
46    @keyframes yhSupportIn {
47      from { opacity: 0; transform: translateY(10px) scale(.98); }
48      to { opacity: 1; transform: none; }
49    }
50
51    .yh-support-head {
52      display: flex; align-items: flex-start; justify-content: space-between;
53      gap: 12px; margin-bottom: 16px;
54    }
55    .yh-support-title {
56      margin: 0; font-size: 20px; font-weight: 700; letter-spacing: -0.3px; color: #ebebeb;
57    }
58    .yh-support-close {
59      display: flex; align-items: center; justify-content: center;
60      width: 30px; height: 30px; flex-shrink: 0; padding: 0;
61      color: #888888; background: #2a2a2a; border: 1px solid #3a3a3a;
62      border-radius: 8px; cursor: pointer;
63      transition: color .2s, background .2s, border-color .2s;
64    }
65    .yh-support-close:hover { color: #ebebeb; background: #313131; border-color: #4a4a4a; }
66    .yh-support-close:focus-visible { outline: 2px solid #8ab4f8; outline-offset: 2px; }
67    .yh-support-close svg { width: 15px; height: 15px; }
68
69    .yh-support-text {
70      margin: 0 0 16px; font-size: 13.5px; line-height: 1.6; color: #b8b8b8;
71    }
72    .yh-support-text.yh-lead { color: #ebebeb; }
73
74    .yh-support-options { display: flex; flex-direction: column; gap: 10px; }
75
76    .yh-support-option {
77      display: flex; align-items: center; gap: 14px; padding: 14px 16px;
78      background: #2a2a2a; border: 1px solid #4a4a4a; border-radius: 8px;
79      box-shadow: 0 1px 2px rgba(0,0,0,.22), 0 2px 5px rgba(0,0,0,.2);
80      text-decoration: none; color: #ebebeb;
81      transition: background .2s cubic-bezier(.4,0,.2,1), border-color .2s cubic-bezier(.4,0,.2,1), transform .15s cubic-bezier(.4,0,.2,1), box-shadow .2s cubic-bezier(.4,0,.2,1);
82    }
83    .yh-support-option:hover {
84      background: #313131; transform: translateY(-1px);
85      box-shadow: 0 4px 14px rgba(0,0,0,.32); color: #ebebeb;
86    }
87    .yh-support-option:focus-visible { outline: 2px solid #8ab4f8; outline-offset: 2px; }
88
89    .yh-support-icon {
90      display: flex; align-items: center; justify-content: center;
91      width: 36px; height: 36px; min-width: 36px; border-radius: 8px;
92      color: #8ab4f8; background: rgba(138, 180, 248, 0.16);
93      border: 1px solid rgba(138, 180, 248, 0.3);
94      transition: background .2s, border-color .2s;
95    }
96    .yh-support-icon svg { width: 17px; height: 17px; }
97
98    .yh-support-option.yh-coffee .yh-support-icon {
99      color: #10b981; background: rgba(16, 185, 129, 0.16); border-color: rgba(16, 185, 129, 0.3);
100    }
101    .yh-support-option.yh-coffee:hover { border-color: rgba(16, 185, 129, 0.6); }
102    .yh-support-option.yh-github:hover { border-color: rgba(138, 180, 248, 0.6); }
103    .yh-support-option.yh-review .yh-support-icon {
104      color: #fbbf24; background: rgba(251, 191, 36, 0.16); border-color: rgba(251, 191, 36, 0.3);
105    }
106    .yh-support-option.yh-review:hover { border-color: rgba(251, 191, 36, 0.6); }
107
108    .yh-support-body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
109    .yh-support-name { font-size: 14px; font-weight: 600; color: #ebebeb; line-height: 1.3; }
110    .yh-support-desc { font-size: 12px; line-height: 1.45; color: #b8b8b8; }
111
112    .yh-support-arrow {
113      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
114      color: #888888; transition: color .2s, transform .2s;
115    }
116    .yh-support-arrow svg { width: 15px; height: 15px; }
117    .yh-support-option:hover .yh-support-arrow { color: #ebebeb; transform: translate(2px, -2px); }
118
119    @media (max-height: 560px) {
120      .yh-support-modal { padding: 12px; }
121      .yh-support-card { padding: 18px; }
122      .yh-support-text { margin-bottom: 12px; }
123      .yh-support-option { padding: 11px 14px; }
124    }
125
126    @media (prefers-reduced-motion: reduce) {
127      .yh-support-scrim, .yh-support-card { animation: none; }
128      .yh-support-option:hover .yh-support-arrow { transform: none; }
129    }
130  `;
131
132  const arrow =
133    '<span class="yh-support-arrow" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none"><path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>';
134
135  const iconCoffee =
136    '<svg viewBox="0 0 24 24" fill="none"><path d="M2 8h15a3 3 0 0 1 0 6h-1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
136<path d="M2 8v9a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 2c-.5 1 -1.5 1.5 -1 3M10 2c-.5 1 -1.5 1.5 -1 3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
137
138  const iconGithub =
139    '<svg viewBox="0 0 24 24" fill="none"><path d="m8 18-6-6 6-6M16 6l6 6-6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
140
141  const iconStar =
142    '<svg viewBox="0 0 24 24" fill="none"><path d="m12 3 2.9 5.9 6.5.9-4.7 4.6 1.1 6.5-5.8-3-5.8 3 1.1-6.5L2.6 9.8l6.5-.9z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
143
144  const options = [
145    {
146      cls: "yh-coffee",
147      icon: iconCoffee,
148      link: KOFI_LINK,
149      name: "Buy me a coffee",
150      desc: "A one-off contribution on Ko-fi. No account and no subscription needed.",
151    },
152    {
153      cls: "yh-github",
154      icon: iconGithub,
155      link: GITHUB_LINK,
156      name: "Contribute on GitHub",
157      desc: "Send a pull request, or report a broken filter with the page it happened on.",
158    },
159    {
160      cls: "yh-review",
161      icon: iconStar,
162      link: REVIEW_LINK,
163      name: "Leave a review",
164      desc: "A rating on the Chrome Web Store costs nothing and helps other people find it.",
165    },
166  ];
167
168  const style = document.createElement("style");
169  style.textContent = css;
170  document.head.appendChild(style);
171
172  const modal = document.createElement("div");
173  modal.className = "yh-support-modal";
174  modal.hidden = true;
175  modal.innerHTML = `
176    <div class="yh-support-scrim" data-support-close></div>
177    <div class="yh-support-card" role="dialog" aria-modal="true" aria-labelledby="yh-support-title">
178      <div class="yh-support-head">
179        <h2 class="yh-support-title" id="yh-support-title">Support YouTube Hider</h2>
180        <button type="button" class="yh-support-close" data-support-close aria-label="Close">
181          <svg viewBox="0 0 24 24" fill="none"><path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
182        </button>
183      </div>
184      <p class="yh-support-text yh-lead">
185        YouTube Hider is free, open source, and has no ads and no tracking. It
186        also aims at a moving target: YouTube reshapes its page markup without
187        warning, and a change nobody announces can quietly break a filter that
188        worked yesterday.
189      </p>
190      <p class="yh-support-text">
191        Keeping it working means hunting those changes down one selector at a
192        time, in someone's spare time. Any of these three helps.
193      </p>
194      <div class="yh-support-options">
195        ${options
196          .map(
197            o => `
198        <a class="yh-support-option ${o.cls}" href="${o.link}" target="_blank" rel="noopener noreferrer">
199          <span class="yh-support-icon" aria-hidden="true">${o.icon}</span>
200          <span class="yh-support-body">
201            <span class="yh-support-name">${o.name}</span>
202            <span class="yh-support-desc">${o.desc}</span>
203          </span>
204          ${arrow}
205        </a>`
206          )
207          .join("")}
208      </div>
209    </div>
210  `;
211
212  document.body.appendChild(modal);
213
214  let lastTrigger = null;
215
216  function open(trigger) {
217    lastTrigger = trigger || null;
218    modal.hidden = false;
219    document.body.style.overflow = "hidden";
220    const close = modal.querySelector(".yh-support-close");
221    if (close) close.focus();
222  }
223
224  function close() {
225    if (modal.hidden) return;
226    modal.hidden = true;
227    document.body.style.overflow = "";
228    if (lastTrigger && typeof lastTrigger.focus === "function") lastTrigger.focus();
229  }
230
231  modal.addEventListener("click", e => {
232    if (e.target.closest("[data-support-close]")) close();
233    else if (e.target.closest(".yh-support-option")) close();
234  });
235
236  document.addEventListener("keydown", e => {
237    if (e.key === "Escape") close();
238  });
239
240  document.addEventListener("click", e => {
241    const trigger = e.target.closest("[data-support-open]");
242    if (!trigger) return;
243    e.preventDefault();
244    open(trigger);
245  });
246})();

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.