Skip to content

Instantly share code, notes, and snippets.

@teidesu
Last active August 10, 2024 16:31
Show Gist options
  • Save teidesu/e1ad8ebcb0a90290e7fd4fcc02403af3 to your computer and use it in GitHub Desktop.
Save teidesu/e1ad8ebcb0a90290e7fd4fcc02403af3 to your computer and use it in GitHub Desktop.
all my homies hate svelte
// ==UserScript==
// @name no svelte
// @description all my homies hate svelte
// @namespace teidesu
// @match *://*/*
// @grant window.close
// @grant GM_addElement
// @grant GM_getValue
// @grant GM_setValue
// @grant GM.getValue
// @grant GM.setValue
// @version 1.1
// @author teidesu
// @downloadURL https://gist.githubusercontent.com/teidesu/e1ad8ebcb0a90290e7fd4fcc02403af3/raw/no-svelte.user.js
// ==/UserScript==
const exportFunction = this.exportFunction ?? (a => a)
let getValue, setValue;
{
let isGM = false
try {
isGM = Boolean(GM)
} catch {}
if (isGM) {
getValue = async function getValue(key) {
return await GM.getValue(key)
}
setValue = async function setValue(key, value) {
return await GM.setValue(key, value)
}
} else {
getValue = async function getValue(key) {
return GM_getValue(key)
}
setValue = async function setValue(key, value) {
return GM_setValue(key, value)
}
}
}
// this.GM_addElement ??
const addElement = window.GM_addElement || function addElement(parent, name, props) {
if (typeof parent === 'string') {
[name, props] = [parent, name]
parent = document.body
}
let element = document.createElement(name)
if (props)
Object.assign(element, props)
parent.appendChild(element)
return element
}
const POPUP_CSS = `
.popup {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 999999999999;
background: #fefefe;
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #222;
color-scheme: light;
}
.title {
font-size: 24px;
font-weight: 600;
margin-bottom: 16px;
}
.subtitle {
font-size: 18px;
margin-bottom: 8px;
}
.question {
font-size: 14px;
margin-bottom: 24px;
}
.buttons {
display: flex;
gap: 12px;
}
.buttons button {
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
margin-bottom: 10px;
color: #222;
}
#button-yes {
background: #fecccc;
}
#button-yes:hover {
background: #febbbb;
}
#button-yes:active {
background: #feaaaa;
}
#button-no {
background: #efefef;
}
#button-no:hover {
background: #dedede;
}
#button-no:active {
background: #cdcdcd;
}
.checkbox {
font-size: 12px;
display: flex;
align-items: center;
gap: 4px;
color: #666;
}
@media (prefers-color-scheme: dark) {
.popup {
background: #202020;
color: #fefefe;
color-scheme: dark;
}
#button-yes {
background: #aa3333;
}
#button-yes:hover {
background: #bb3333;
}
#button-yes:active {
background: #cc3333;
}
#button-no {
background: #404040;
}
#button-no:hover {
background: #505050;
}
#button-no:active {
background: #606060;
}
}
`.trim()
const POPUP_HTML = ({ svelteVersion }) => `
<div class="popup">
<div class="title">Hol' up!</div>
<div class="subtitle">💩 This page uses Svelte (v${svelteVersion})</div>
<div class="question">Do you <i>really</i> want to proceed?</div>
<div class="buttons">
<button id="button-yes">Yes</button>
<button id="button-no">No</button>
</div>
<div class="checkbox">
<input type="checkbox" id="remember">
<label for="remember">Remember my choice</label>
</div>
</div>
`.trim()
const STORAGE_KEY = `no-svelte:${location.hostname}`
async function displayPopup(svelteVersion) {
const stored = await getValue(STORAGE_KEY)
if (stored === 'yes') return
if (stored === 'no') return window.close()
const popupWrap = addElement('no-svelte-host')
const shadow = popupWrap.attachShadow({ mode: 'open' })
const popup = addElement(shadow, 'div')
popup.innerHTML = POPUP_HTML({ svelteVersion })
addElement(popup, 'style', { textContent: POPUP_CSS })
const oldBodyOverflow = document.body.style.overflow
document.body.style.overflow = 'hidden'
const remember = () => popup.querySelector('#remember').checked
popup.querySelector('#button-yes').addEventListener('click', async () => {
if (remember())
await setValue(STORAGE_KEY, 'yes')
popupWrap.remove();
document.body.style.overflow = oldBodyOverflow
})
popup.querySelector('#button-no').addEventListener('click', async () => {
if (remember())
await setValue(STORAGE_KEY, 'no')
window.close()
})
}
function detectSvelte(unsafeSvelte) {
let firstValue = unsafeSvelte.v.values().next().value
if (firstValue !== undefined) {
displayPopup(firstValue)
} else {
unsafeSvelte.v.add = exportFunction(function(v) {
displayPopup(v)
if (this.wrappedJSObject)
delete this.wrappedJSObject.add
else
delete this.add
Reflect.apply(unsafeWindow.Set.prototype.add, this, [v])
}, unsafeSvelte)
}
}
if (unsafeWindow.__svelte) {
detectSvelte(unsafeWindow.__svelte)
} else {
let svelte
const exportedGet = exportFunction(() => {
return svelte
}, unsafeWindow)
const exportedSet = exportFunction((v) => {
if (v.wrappedJSObject)
v = v.wrappedJSObject
detectSvelte(v)
svelte = v
return true
}, unsafeWindow)
Object.defineProperty(unsafeWindow, '__svelte', {
get: exportedGet,
set: exportedSet
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment