您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Красивейшее всплывающее окно поверх страницы с ссылкой на новое расширение FunPay Tools. Закрывается кликом/ESC, можно "не показывать снова".
// ==UserScript== // @name FunPay — Ultra Modal: "Новое расширение!" // @namespace https://funpay.com/ // @version 9.0.0 // @description Красивейшее всплывающее окно поверх страницы с ссылкой на новое расширение FunPay Tools. Закрывается кликом/ESC, можно "не показывать снова". // @author you // @match https://funpay.com/* // @match https://*.funpay.com/* // @run-at document-idle // @grant none // ==/UserScript== (function () { "use strict"; // ---------- SETTINGS ---------- const STORE_URL = "https://chromewebstore.google.com/detail/funpay-tools/pibmnjjfpojnakckilflcboodkndkibb/"; const STORAGE_KEY = "fpt_ultra_modal_dismissed"; const REMIND_AFTER_DAYS = 7; // спустя сколько дней снова показать, если было "Не показывать" const HOTKEY = { altKey: true, key: "f" }; // Alt+F — снова открыть модалку вручную // Показать снова, если прошло N дней try { const raw = localStorage.getItem(STORAGE_KEY); if (raw) { const { ts } = JSON.parse(raw); const days = (Date.now() - ts) / (1000 * 60 * 60 * 24); if (days < REMIND_AFTER_DAYS) return; } } catch (_) {} // Дождаться готовности body if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init, { once: true }); } else { init(); } // ----------- MAIN ------------ function init() { // Shadow DOM, чтобы стили ни с чем не конфликтовали const host = document.createElement("div"); host.style.all = "initial"; host.style.position = "fixed"; host.style.inset = "0"; host.style.zIndex = "999999999"; // поверх всего host.style.pointerEvents = "none"; // пока не вставим слои document.documentElement.appendChild(host); const shadow = host.attachShadow({ mode: "open" }); // Backdrop + контейнер const wrapper = document.createElement("div"); wrapper.className = "fp-wrapper"; wrapper.innerHTML = ` <div class="fp-backdrop"></div> <div class="fp-center"> <div class="fp-card"> <button class="fp-close" aria-label="Закрыть">✕</button> <div class="fp-badge"> <span class="fp-pulse"></span> <span class="fp-badge-text">Новинка</span> </div> <div class="fp-title"> Внимание! Вышло <span class="grad">новое расширение</span> </div> <div class="fp-subtitle"> Ваш старый юзерскрипт — <em>древняя хуйня</em> и уже устарел. Переходите на <strong>FunPay Tools</strong> — быстрее, удобнее, красивее. </div> <div class="fp-feats"> <div class="feat"> <div class="dot"></div> Свежие фичи </div> <div class="feat"> <div class="dot"></div> Ноль танцев с бубном </div> <div class="feat"> <div class="dot"></div> Поддержка и стабильность </div> </div> <div class="fp-actions"> <a class="fp-primary" href="${STORE_URL}" target="_blank" rel="noopener"> Установить FunPay Tools </a> <button class="fp-ghost" data-close>Позже</button> </div> <label class="fp-checkbox"> <input type="checkbox" class="fp-nomore" /> Не показывать снова </label> </div> </div> `; shadow.appendChild(style()); shadow.appendChild(wrapper); // Включаем клики host.style.pointerEvents = "auto"; // Закрытия const closeModal = () => { wrapper.classList.add("fp-hide"); setTimeout(() => host.remove(), 220); // запомнить, если включен чекбокс const noMore = shadow.querySelector(".fp-nomore"); if (noMore && noMore.checked) { try { localStorage.setItem( STORAGE_KEY, JSON.stringify({ ts: Date.now() }) ); } catch (_) {} } // убрать обработчик хоткея window.removeEventListener("keydown", onKey); }; const onKey = (e) => { // ESC закрыть if (e.key === "Escape") closeModal(); // Alt+F — снова открыть (работает до закрытия) if ( e.key.toLowerCase() === HOTKEY.key && !!e.altKey === HOTKEY.altKey ) { // Ничего: модал уже открыт. Подсветим кнопку. const primary = shadow.querySelector(".fp-primary"); if (primary) { primary.classList.add("fp-wiggle"); setTimeout(() => primary.classList.remove("fp-wiggle"), 600); } } }; shadow.querySelector(".fp-backdrop")?.addEventListener("click", closeModal); shadow.querySelector(".fp-close")?.addEventListener("click", closeModal); shadow.querySelector("[data-close]")?.addEventListener("click", closeModal); window.addEventListener("keydown", onKey, false); // Лёгкий вход-анимация requestAnimationFrame(() => wrapper.classList.add("fp-show")); } // ---------- STYLES ---------- function style() { const el = document.createElement("style"); el.textContent = ` @keyframes fpFadeIn { from { opacity: 0 } to { opacity: 1 } } @keyframes fpPop { 0% { transform: translateY(6px) scale(.96); opacity: 0 } 100% { transform: translateY(0) scale(1); opacity: 1 } } @keyframes fpGlow { 0% { filter: drop-shadow(0 0 0px rgba(255,255,255,.0)); } 100% { filter: drop-shadow(0 0 18px rgba(255,255,255,.35)); } } @keyframes fpPulse { 0% { transform: scale(1); opacity: .9 } 50% { transform: scale(1.18); opacity: .5 } 100% { transform: scale(1); opacity: .9 } } @keyframes fpWiggle { 0%,100%{ transform: translateX(0) } 25%{ transform: translateX(-4px) } 75%{ transform: translateX(4px) } } :host, .fp-wrapper { all: initial; } .fp-wrapper { position: fixed; inset: 0; display: grid; place-items: center; opacity: 0; transition: opacity .2s ease; } .fp-wrapper.fp-show { opacity: 1; animation: fpFadeIn .2s ease both; } .fp-wrapper.fp-hide { opacity: 0; } .fp-backdrop { position: absolute; inset: 0; background: radial-gradient(80vmax 80vmax at center, rgba(24,24,27,.65), rgba(0,0,0,.55) 60%, rgba(0,0,0,.75)); backdrop-filter: blur(8px) saturate(120%); } .fp-center { position: relative; width: min(92vw, 720px); padding: 24px; } .fp-card { position: relative; border-radius: 24px; padding: 28px clamp(20px, 4vw, 36px); background: linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.05)), radial-gradient(120% 120% at 0% 0%, rgba(255,255,255,.08), transparent 40%), rgba(24,24,27,.72); color: #fff; box-shadow: 0 20px 40px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.08); backdrop-filter: blur(16px) saturate(140%); animation: fpPop .25s ease both, fpGlow 1.2s ease .2s both; overflow: clip; } /* Неоновая граница */ .fp-card::before { content: ""; position: absolute; inset: -1px; border-radius: 26px; padding: 1px; background: linear-gradient(135deg, #a78bfa, #60a5fa 20%, #34d399 40%, #f59e0b 60%, #f472b6 80%, #a78bfa); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; filter: blur(.4px) saturate(140%); } .fp-close { position: absolute; top: 10px; right: 10px; width: 36px; height: 36px; border-radius: 10px; border: none; cursor: pointer; font-size: 18px; line-height: 1; background: rgba(255,255,255,.08); color: #fff; transition: transform .15s ease, background .2s ease, opacity .2s ease; } .fp-close:hover { transform: scale(1.06); background: rgba(255,255,255,.14); } .fp-close:active { transform: scale(.98); opacity: .9; } .fp-badge { position: relative; display: inline-flex; align-items: center; gap: 10px; margin-bottom: 12px; padding: 8px 12px; border-radius: 999px; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.14); } .fp-pulse { width: 10px; height: 10px; border-radius: 999px; background: #34d399; box-shadow: 0 0 16px #34d399; animation: fpPulse 1.6s ease-in-out infinite; } .fp-badge-text { font-weight: 600; letter-spacing: .3px; } .fp-title { font-size: clamp(24px, 3.4vw, 36px); font-weight: 800; line-height: 1.15; margin-bottom: 10px; letter-spacing: .2px; } .grad { background: linear-gradient(135deg, #a78bfa, #60a5fa, #34d399, #f472b6); -webkit-background-clip: text; background-clip: text; color: transparent; } .fp-subtitle { opacity: .95; font-size: clamp(14px, 2vw, 16px); line-height: 1.6; margin-bottom: 18px; } .fp-subtitle em { font-style: normal; opacity: .9; text-decoration: underline wavy rgba(255,255,255,.35); } .fp-subtitle strong { font-weight: 800; } .fp-feats { display: grid; grid-template-columns: 1fr; gap: 10px; margin: 14px 0 22px; } @media (min-width: 520px) { .fp-feats { grid-template-columns: 1fr 1fr 1fr; } } .feat { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 12px; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .feat .dot { width: 8px; height: 8px; border-radius: 999px; background: #60a5fa; box-shadow: 0 0 8px rgba(96,165,250,.9); } .fp-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; } .fp-primary, .fp-ghost { appearance: none; border: none; cursor: pointer; padding: 12px 16px; border-radius: 14px; font-weight: 700; text-decoration: none; transition: transform .12s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease; will-change: transform; } .fp-primary { background: linear-gradient(135deg, #6366f1, #22c55e); color: #fff; box-shadow: 0 12px 22px rgba(34,197,94,.25), 0 6px 12px rgba(99,102,241,.25); } .fp-primary:hover { transform: translateY(-1px); } .fp-primary:active { transform: translateY(0); opacity: .92; } .fp-primary.fp-wiggle { animation: fpWiggle .6s ease both; } .fp-ghost { background: rgba(255,255,255,.08); color: #fff; border: 1px solid rgba(255,255,255,.14); } .fp-ghost:hover { background: rgba(255,255,255,.12); transform: translateY(-1px); } .fp-ghost:active { transform: translateY(0); opacity: .95; } .fp-checkbox { display: inline-flex; align-items: center; gap: 8px; opacity: .85; user-select: none; cursor: pointer; } .fp-checkbox input { width: 16px; height: 16px; accent-color: #22c55e; cursor: pointer; } `; return el; } })();