您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show vintage post card/"Greetings from.." location name popup on https://neal.fun/internet-roadtrip/
// ==UserScript== // @name Internet Roadtrip: "Greetings from" popup // @namespace http://tampermonkey.net/ // @version 1.1.2 // @author joawatte19 // @description Show vintage post card/"Greetings from.." location name popup on https://neal.fun/internet-roadtrip/ // @match https://neal.fun/internet-roadtrip/ // @license MIT // @grant none // @run-at document-end // @require https://cdn.jsdelivr.net/npm/[email protected] // ==/UserScript== (async () => { if (!IRF?.isInternetRoadtrip) return; const container = await IRF.vdom.container; window.container = container; const originalUpdateData = container.methods.updateData; let lastLoc = {}; let shown = { neighborhood: null, county: null }; container.state.updateData = new Proxy(originalUpdateData, { apply: (target, thisArg, args) => { const result = Reflect.apply(target, thisArg, args); const loc = container.state.currentLocation; const fields = ["neighborhood", "county", "state", "country"]; const changedFields = fields.filter(field => loc?.[field] && loc[field] !== lastLoc[field]); lastLoc = { ...loc }; if (changedFields.length) { const field = changedFields[0]; const title = loc[field]; const fieldHierarchy = { neighborhood: "county", county: "state", state: "country", country: "state" }; const parentField = fieldHierarchy[field]; const subtitle = loc[parentField] && loc[parentField] !== title ? loc[parentField] : ""; const isOnceOnly = ["neighborhood", "county"].includes(field); const wasShownBefore = shown[field] === title; if (!isOnceOnly || !wasShownBefore) { showPopup(title, subtitle); if (isOnceOnly) shown[field] = title; } } return result; } }); // Load fonts once at script start const fontLink = document.createElement("link"); fontLink.href = "https://fonts.googleapis.com/css2?family=Anton&family=Pacifico&display=swap"; fontLink.rel = "stylesheet"; document.head.appendChild(fontLink); function showPopup(title, subtitle = "") { const existing = document.getElementById("ds-location-popup"); if (existing) existing.remove(); const overlay = document.createElement("div"); overlay.id = "ds-overlay"; Object.assign(overlay.style, { position: "fixed", top: "0", left: "0", width: "100vw", height: "100vh", backgroundColor: "#000", opacity: "0", zIndex: 9998, pointerEvents: "none", transition: "opacity 1.2s ease-in-out", }); document.body.appendChild(overlay); requestAnimationFrame(() => { overlay.style.opacity = "0.4"; }); // Load fonts const fontLink = document.createElement("link"); fontLink.href = "https://fonts.googleapis.com/css2?family=Anton&family=Pacifico&display=swap"; fontLink.rel = "stylesheet"; document.head.appendChild(fontLink); // Create popup const popup = document.createElement("div"); popup.id = "ds-location-popup"; popup.innerHTML = ` <div style="font-family: 'Pacifico', cursive; font-size: 2.5rem; color: #002B5B; margin-bottom: 0.5rem;"> Greetings from </div> <svg viewBox="0 0 1200 600" style="width: 100%; max-width: 1200; height: auto; transform: rotate(-8deg); display: block; margin: 0 auto;"> <defs> <pattern id="bgImage" patternUnits="userSpaceOnUse" width="1200" height="600"> <image href="https://files.catbox.moe/2rlllj.png" x="0" y="0" width="1200" height="600" preserveAspectRatio="xMidYMid slice" /> </pattern> <path id="textPath" d="M10,500 Q500,100 1300,300" fill="none" /> </defs> <!-- Orange 3D shadow --> <text fill="orange" font-size="300" font-family="Anton, sans-serif" letter-spacing="-2"> <textPath href="#textPath" startOffset="50%" text-anchor="middle"> ${title} </textPath> </text> <!-- White outline --> <text fill="white" stroke="white" stroke-width="10" font-size="299" font-family="Anton, sans-serif" letter-spacing="-2"> <textPath href="#textPath" startOffset="50%" text-anchor="middle"> ${title} </textPath> </text> <!-- Clipped image fill --> <text fill="url(#bgImage)" font-size="298" font-family="Anton, sans-serif" letter-spacing="-2"> <textPath href="#textPath" startOffset="50%" text-anchor="middle"> ${title} </textPath> </text> </svg> ${subtitle ? `<div style="font-family: 'Pacifico', cursive; font-size: 2rem; color: #002B5B; margin-top: 0.5rem;">${subtitle}</div>` : ""} `; Object.assign(popup.style, { position: "fixed", top: "40%", left: "50%", transform: "translate(-50%, -50%) scale(0.95)", whiteSpace: "normal", maxWidth: "90vw", textAlign: "center", userSelect: "none", zIndex: 9999, opacity: "0", transition: "opacity 1.2s ease-in-out, transform 1.2s ease-in-out", pointerEvents: "none", padding: "1rem", borderBottom: "4px solid rgba(227,226,224,0.5)", }); document.body.appendChild(popup); requestAnimationFrame(() => { popup.style.opacity = "1"; popup.style.transform = "translate(-50%, -50%) scale(1)"; }); // fade out setTimeout(() => { popup.style.opacity = "0"; popup.style.transform = "translate(-50%, -50%) scale(1.05) rotate(-2deg)"; overlay.style.opacity = "0"; setTimeout(() => { popup.remove(); overlay.remove(); }, 1500); }, 3000); } window.showPopup = showPopup; // manual trigger with console window.showDSLocationPopup = () => { const loc = container.state.currentLocation; if (!loc) { console.warn("No location data available."); return; } const fields = ["neighborhood", "county", "state", "country"]; for (const field of fields) { if (loc[field]) { showPopup(loc[field]); break; } } }; })();