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.