Migrating popup to svelte

This commit is contained in:
ManeraKai 2024-07-25 15:17:57 +03:00
parent e6a58409ff
commit c6de68c4c4
No known key found for this signature in database
GPG Key ID: 5ABC31FFD562E337
53 changed files with 517 additions and 717 deletions

3
.gitignore vendored
View File

@ -4,7 +4,6 @@ nod
node_modules
package-lock.json
.vscode
src/pages/options/index.html
src/pages/popup/popup.html
pnpm-lock.yaml
src/pages/options/build
src/pages/popup/build

View File

@ -3,8 +3,8 @@
"type": "module",
"description": "Redirects YouTube, Twitter, TikTok and more to privacy friendly frontends.",
"engines": {
"node": ">=16.13.1",
"npm": ">=8.1.2"
"node": ">=18.20.4",
"npm": ">=10.7.0"
},
"scripts": {
"start": "web-ext run",
@ -12,7 +12,7 @@
"android": "web-ext run -t firefox-android --adb-device emulator-5554 --firefox-apk org.mozilla.fenix",
"build": "web-ext build",
"test": "web-ext lint",
"html": "rollup -c"
"html": "rollup -c --config-popup && rollup -c --config-options"
},
"repository": {
"type": "git",
@ -25,16 +25,7 @@
},
"homepage": "https://libredirect.github.io",
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-terser": "^0.4.0",
"prettier": "3.3.3",
"pug-cli": "^1.0.0-alpha6",
"rollup": "^3.15.0",
"rollup-plugin-css-only": "^4.3.0",
"rollup-plugin-svelte": "^7.1.2",
"svelte": "^3.55.0",
"web-ext": "^7.2.0"
"prettier": "3.3.3"
},
"webExt": {
"sourceDir": "./src/",
@ -46,6 +37,15 @@
}
},
"dependencies": {
"svelte-select": "^5.8.3"
"svelte-select": "^5.8.3",
"pug-cli": "^1.0.0-alpha6",
"rollup": "^3.15.0",
"rollup-plugin-css-only": "^4.3.0",
"rollup-plugin-svelte": "^7.1.2",
"svelte": "^3.55.0",
"web-ext": "^7.2.0",
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-terser": "^0.4.0"
}
}

View File

@ -5,14 +5,23 @@ import resolve from "@rollup/plugin-node-resolve"
import css from "rollup-plugin-css-only"
const production = !process.env.ROLLUP_WATCH
let input
let output
if (process.argv.includes("--config-options")) {
input = "src/pages/options_src/main.js"
output = "src/pages/options/build/bundle.js"
} else if (process.argv.includes("--config-popup")) {
input = "src/pages/popup_src/main.js"
output = "src/pages/popup/build/bundle.js"
}
export default {
input: "src/pages/src/main.js",
input,
output: {
sourcemap: true,
format: "iife",
name: "app",
file: "src/pages/options/build/bundle.js",
file: output,
},
plugins: [
svelte({
@ -27,7 +36,7 @@ export default {
exportConditions: ["svelte"],
}),
commonjs(),
// production && terser(),
production && terser(),
],
watch: {
clearScreen: false,

View File

@ -27,7 +27,7 @@
"browser_action": {
"default_title": "__MSG_extensionName__",
"browser_style": false,
"default_popup": "pages/popup/popup.html",
"default_popup": "pages/popup/index.html",
"default_icon": {
"16": "assets/images/libredirect-16.png",
"32": "assets/images/libredirect-32.png",

View File

@ -3,7 +3,7 @@
export let onChange
</script>
<input bind:checked on:change={onChange} type="checkbox" />
<input {...$$restProps} bind:checked on:change={onChange} type="checkbox" />
<style>
input[type="checkbox"] {

View File

@ -1,4 +1,4 @@
<div {...$$props}>
<div {...$$props} on:click>
<slot></slot>
</div>

View File

Before

Width:  |  Height:  |  Size: 577 B

After

Width:  |  Height:  |  Size: 577 B

View File

Before

Width:  |  Height:  |  Size: 166 B

After

Width:  |  Height:  |  Size: 166 B

View File

Before

Width:  |  Height:  |  Size: 233 B

After

Width:  |  Height:  |  Size: 233 B

View File

@ -0,0 +1,12 @@
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
width="24px"
viewBox="0 0 24 24"
preserveAspectRatio="xMinYMin meet"
fill="currentColor"
>
<path
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"
/>
</svg>

After

Width:  |  Height:  |  Size: 313 B

View File

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 274 B

View File

Before

Width:  |  Height:  |  Size: 720 B

After

Width:  |  Height:  |  Size: 720 B

View File

@ -0,0 +1,10 @@
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
width="24px"
viewBox="0 0 24 24"
preserveAspectRatio="xMinYMin meet"
fill="currentColor"
>
<path d="M7 20v-9q0-.825.588-1.413Q8.175 9 9 9h8.2l-1.6-1.6L17 6l4 4-4 4-1.4-1.4 1.6-1.6H9v9Z" />
</svg>

After

Width:  |  Height:  |  Size: 264 B

View File

@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
width="24px"
viewBox="0 0 24 24"
preserveAspectRatio="xMinYMin meet"
fill="currentColor"
>
<path
d="M 17,20 V 11 Q 17,10.175 16.412,9.587 15.825,9 15,9 H 6.8 L 8.4,7.4 7,6 3,10 7,14 8.4,12.6 6.8,11 H 15 v 9 z"
id="path2"
/>
</svg>

After

Width:  |  Height:  |  Size: 309 B

View File

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 436 B

View File

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 354 B

View File

@ -0,0 +1,12 @@
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
width="24px"
viewBox="0 0 24 24"
preserveAspectRatio="xMinYMin meet"
fill="currentColor"
>
<path
d="m9.25 22-.4-3.2q-.325-.125-.612-.3-.288-.175-.563-.375L4.7 19.375l-2.75-4.75 2.575-1.95Q4.5 12.5 4.5 12.337v-.675q0-.162.025-.337L1.95 9.375l2.75-4.75 2.975 1.25q.275-.2.575-.375.3-.175.6-.3l.4-3.2h5.5l.4 3.2q.325.125.613.3.287.175.562.375l2.975-1.25 2.75 4.75-2.575 1.95q.025.175.025.337v.675q0 .163-.05.338l2.575 1.95-2.75 4.75-2.95-1.25q-.275.2-.575.375-.3.175-.6.3l-.4 3.2Zm2.8-6.5q1.45 0 2.475-1.025Q15.55 13.45 15.55 12q0-1.45-1.025-2.475Q13.5 8.5 12.05 8.5q-1.475 0-2.488 1.025Q8.55 10.55 8.55 12q0 1.45 1.012 2.475Q10.575 15.5 12.05 15.5Z"
/>
</svg>

After

Width:  |  Height:  |  Size: 732 B

View File

@ -0,0 +1,15 @@
<svg
{...$$restProps}
xmlns="http://www.w3.org/2000/svg"
height="24px"
width="24px"
viewBox="0 0 24 24"
preserveAspectRatio="xMinYMin meet"
fill="currentColor"
on:click
on:keydown={null}
>
<path
d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"
/>
</svg>

After

Width:  |  Height:  |  Size: 459 B

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<link rel="icon" type="image/x-icon" href="../../../assets/images/libredirect.svg">
<title>Settings</title>
<link rel='stylesheet' href='build/bundle.css'>
<script defer src='build/bundle.js'></script>
</head>
<body>
</body>
</html>

View File

@ -1,51 +1,8 @@
window.browser = window.browser || window.chrome
import localise from "../../assets/javascripts/localise.js"
import utils from "../../assets/javascripts/utils.js"
import servicesHelper from "../../assets/javascripts/services.js"
if (!(await utils.getOptions())) {
await servicesHelper.initDefaults()
}
async function changeTheme() {
switch ((await utils.getOptions()).theme) {
case "dark":
document.body.classList.add("dark-theme")
document.body.classList.remove("light-theme")
for (const element of document.body.getElementsByClassName("dark")) {
element.style.display = "none"
}
break
case "light":
document.body.classList.add("light-theme")
document.body.classList.remove("dark-theme")
for (const element of document.body.getElementsByClassName("light")) {
element.style.display = "none"
}
break
default:
if (matchMedia("(prefers-color-scheme: light)").matches) {
document.body.classList.add("light-theme")
document.body.classList.remove("dark-theme")
for (const element of document.body.getElementsByClassName("light")) {
element.style.display = "none"
}
} else {
document.body.classList.add("dark-theme")
document.body.classList.remove("light-theme")
for (const element of document.body.getElementsByClassName("dark")) {
element.style.display = "none"
}
}
}
}
changeTheme()
if (["ar", "iw", "ku", "fa", "ur"].includes(browser.i18n.getUILanguage())) {
document.getElementsByTagName("body")[0].classList.add("rtl")
document.getElementsByTagName("body")[0].dir = "rtl"
}
localise.localisePage()
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", changeTheme)

View File

@ -93,6 +93,7 @@
{/if}
<style>
:global(body) {
width: 100vw;
height: 100vh;

View File

@ -1,10 +1,10 @@
<script>
import Row from "../components/Row.svelte"
import Select from "../components/Select.svelte"
import AddIcon from "../icons/AddIcon.svelte"
import CloseIcon from "../icons/CloseIcon.svelte"
import Input from "../components/Input.svelte"
import Label from "../components/Label.svelte"
import Row from "../../components/Row.svelte"
import Select from "../../components/Select.svelte"
import AddIcon from "../../icons/AddIcon.svelte"
import CloseIcon from "../../icons/CloseIcon.svelte"
import Input from "../../components/Input.svelte"
import Label from "../../components/Label.svelte"
import { options, config } from "../stores"
import { onDestroy } from "svelte"

View File

@ -3,8 +3,8 @@
import Exceptions from "./Exceptions.svelte"
import SettingsButtons from "./SettingsButtons.svelte"
import RowSelect from "../components/RowSelect.svelte"
import Checkbox from "../components/RowCheckbox.svelte"
import RowSelect from "../../components/RowSelect.svelte"
import Checkbox from "../../components/RowCheckbox.svelte"
import { options } from "../stores"
import { onDestroy } from "svelte"

View File

@ -2,10 +2,10 @@
let browser = window.browser || window.chrome
import { onDestroy } from "svelte"
import Button from "../components/Button.svelte"
import ExportIcon from "../icons/ExportIcon.svelte"
import ImportIcon from "../icons/ImportIcon.svelte"
import ResetIcon from "../icons/ResetIcon.svelte"
import Button from "../../components/Button.svelte"
import ExportIcon from "../../icons/ExportIcon.svelte"
import ImportIcon from "../../icons/ImportIcon.svelte"
import ResetIcon from "../../icons/ResetIcon.svelte"
import { options } from "../stores"
import servicesHelper from "../../../assets/javascripts/services.js"
import utils from "../../../assets/javascripts/utils.js"

View File

@ -1,14 +1,14 @@
<script>
let browser = window.browser || window.chrome
import Button from "../components/Button.svelte"
import AddIcon from "../icons/AddIcon.svelte"
import Button from "../../components/Button.svelte"
import AddIcon from "../../icons/AddIcon.svelte"
import { options, config } from "../stores"
import PingIcon from "../icons/PingIcon.svelte"
import Row from "../components/Row.svelte"
import Input from "../components/Input.svelte"
import Label from "../components/Label.svelte"
import CloseIcon from "../icons/CloseIcon.svelte"
import PingIcon from "../../icons/PingIcon.svelte"
import Row from "../../components/Row.svelte"
import Input from "../../components/Input.svelte"
import Label from "../../components/Label.svelte"
import CloseIcon from "../../icons/CloseIcon.svelte"
import { onDestroy, onMount } from "svelte"
import utils from "../../../assets/javascripts/utils"

View File

@ -1,11 +1,11 @@
<script>
import { onDestroy } from "svelte"
import RowSelect from "../components/RowSelect.svelte"
import RowSelect from "../../components/RowSelect.svelte"
import SvelteSelect from "svelte-select"
import { options, config } from "../stores"
import Row from "../components/Row.svelte"
import Label from "../components/Label.svelte"
import Row from "../../components/Row.svelte"
import Label from "../../components/Label.svelte"
import FrontendIcon from "./FrontendIcon.svelte"
let _options

View File

@ -24,14 +24,17 @@
theme = "light"
}
}
$: imageType = _config.services[details.value].imageType
</script>
{#if _config.services[details.value].imageType == "svgMono"}
{#if theme == "dark"}
<img src={`/assets/images/${details.value}-icon-light.svg`} alt={details.label} />
{#if imageType}
{#if imageType == "svgMono"}
{#if theme == "dark"}
<img src={`/assets/images/${details.value}-icon-light.svg`} alt={details.label} />
{:else}
<img src={`/assets/images/${details.value}-icon.svg`} alt={details.label} />
{/if}
{:else}
<img src={`/assets/images/${details.value}-icon.svg`} alt={details.label} />
<img src={`/assets/images/${details.value}-icon.${imageType}`} alt={details.label} />
{/if}
{:else}
<img src={`/assets/images/${details.value}-icon.${_config.services[details.value].imageType}`} alt={details.label} />
{/if}

View File

@ -1,9 +1,9 @@
<script>
import Checkbox from "../components/RowCheckbox.svelte"
import RowSelect from "../components/RowSelect.svelte"
import Row from "../components/Row.svelte"
import Label from "../components/Label.svelte"
import Select from "../components/Select.svelte"
import Checkbox from "../../components/RowCheckbox.svelte"
import RowSelect from "../../components/RowSelect.svelte"
import Row from "../../components/Row.svelte"
import Label from "../../components/Label.svelte"
import Select from "../../components/Select.svelte"
import { options, config } from "../stores"
import RedirectType from "./RedirectType.svelte"
import { onDestroy } from "svelte"

View File

@ -1,8 +1,8 @@
<script>
import { page } from "./stores"
import GeneralIcon from "./icons/GeneralIcon.svelte"
import ServicesIcon from "./icons/ServicesIcon.svelte"
import AboutIcon from "./icons/AboutIcon.svelte"
import GeneralIcon from "../icons/GeneralIcon.svelte"
import ServicesIcon from "../icons/ServicesIcon.svelte"
import AboutIcon from "../icons/AboutIcon.svelte"
</script>
<div>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<link rel="icon" type="image/x-icon" href="../../../assets/images/libredirect.svg">
<title>Settings</title>
<link rel='stylesheet' href='build/bundle.css'>
<link rel='stylesheet' href='../stylesheets/styles.css'>
<script defer src='build/bundle.js'></script>
</head>
<body>
</body>
</html>

View File

@ -1,119 +0,0 @@
"use strict"
window.browser = window.browser || window.chrome
import servicesHelper from "../../assets/javascripts/services.js"
import utils from "../../assets/javascripts/utils.js"
document.getElementById("more-options").href = browser.runtime.getURL("pages/options/index.html")
document.getElementById("more-options").setAttribute("target", "_blank")
await browser.runtime.getPlatformInfo(r => {
switch (r.os) {
case "fuchsia":
case "ios":
case "android":
document.getElementsByTagName("html")[0].classList.add("mobile")
}
})
const allSites = document.getElementById("all_sites")
const currSite = document.getElementById("current_site")
const currentSiteDivider = document.getElementById("current_site_divider")
const config = await utils.getConfig()
const divs = {}
for (const service in config.services) {
divs[service] = {}
divs[service].all = allSites.getElementsByClassName(service)[0]
divs[service].current = currSite.getElementsByClassName(service)[0]
divs[service].all_toggle = allSites.getElementsByClassName(`${service}-enabled`)[0]
divs[service].all_toggle.addEventListener("change", async () => {
const options = await utils.getOptions()
options[service].enabled = divs[service].all_toggle.checked
browser.storage.local.set({ options })
})
allSites.getElementsByClassName(`${service}-change_instance`)[0].addEventListener("click", () => {
browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) {
const url = new URL(tabs[0].url)
browser.tabs.update({ url: await servicesHelper.switchInstance(url, service) })
}
})
})
divs[service].current_toggle = currSite.getElementsByClassName(`${service}-enabled`)[0]
divs[service].current_toggle.addEventListener("change", async () => {
const options = await utils.getOptions()
options[service].enabled = divs[service].current_toggle.checked
browser.storage.local.set({ options })
})
currSite.getElementsByClassName(`${service}-change_instance`)[0].addEventListener("click", () => {
browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) {
const url = new URL(tabs[0].url)
browser.tabs.update({ url: await servicesHelper.switchInstance(url, service) })
}
})
})
}
browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
// Set visibility of control buttons
if (tabs[0].url) {
const hr = document.getElementById("hr")
var url = new URL(tabs[0].url)
servicesHelper.switchInstance(url).then(r => {
if (r) {
document.getElementById("change_instance_div").style.display = ""
hr.style.display = ""
document
.getElementById("change_instance")
.addEventListener("click", async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url) }))
}
})
servicesHelper.reverse(url).then(r => {
if (r) {
hr.style.display = ""
document.getElementById("copy_original_div").style.display = ""
document.getElementById("copy_original").addEventListener("click", () => servicesHelper.copyRaw(url))
document.getElementById("redirect_to_original_div").style.display = ""
document
.getElementById("redirect_to_original")
.addEventListener("click", () => browser.runtime.sendMessage("reverseTab"))
}
})
servicesHelper.redirectAsync(url, "main_frame", null, true).then(r => {
if (r) {
document.getElementById("redirect_div").style.display = ""
hr.style.display = ""
document.getElementById("redirect").addEventListener("click", () => browser.runtime.sendMessage("redirectTab"))
}
})
}
const options = await utils.getOptions()
// Set visibility of all service buttons
for (const service of options.popupServices) {
divs[service].all.classList.remove("hide")
divs[service].all_toggle.checked = options[service].enabled
}
// Set visibility of current page service button
if (url) {
const service = await servicesHelper.computeService(url)
if (service) {
divs[service].all.classList.add("hide")
divs[service].current.classList.remove("hide")
divs[service].current_toggle.checked = options[service].enabled
currentSiteDivider.style.display = ""
}
}
})

View File

@ -1,53 +0,0 @@
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
link(href="../stylesheets/styles.css" rel="stylesheet")
link(href="./style.css" rel="stylesheet")
body(dir="auto")
div(class="block" id="change_instance_div" style="display: none")
button(class="title button bottom-button" id="change_instance")
label(data-localise="__MSG_switchInstance__") Switch Instance
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z")
div(class="block" id="copy_original_div" title="Copy the original redirected link" style="display: none")
button(class="title button bottom-button" id="copy_original")
label() Copy Original
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z")
div(class="block" id="redirect_div" style="display: none")
button(class="title button bottom-button" id="redirect")
label Redirect
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="M7 20v-9q0-.825.588-1.413Q8.175 9 9 9h8.2l-1.6-1.6L17 6l4 4-4 4-1.4-1.4 1.6-1.6H9v9Z")
div(class="block" id="redirect_to_original_div" style="display: none")
button(class="title button bottom-button" id="redirect_to_original")
label Redirect To Original
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="M 17,20 V 11 Q 17,10.175 16.412,9.587 15.825,9 15,9 H 6.8 L 8.4,7.4 7,6 3,10 7,14 8.4,12.6 6.8,11 H 15 v 9 z" id="path2")
hr(id="hr" style="display: none")
div(id="current_site")
include /src/pages/popup/switches
div(id="current_site_divider" style="display: none")
hr
div(id="all_sites")
include /src/pages/popup/switches
hr
div(class="block")
a(class="title button bottom-button" id="more-options")
label(data-localise="__MSG_settings__") Settings
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="m9.25 22-.4-3.2q-.325-.125-.612-.3-.288-.175-.563-.375L4.7 19.375l-2.75-4.75 2.575-1.95Q4.5 12.5 4.5 12.337v-.675q0-.162.025-.337L1.95 9.375l2.75-4.75 2.975 1.25q.275-.2.575-.375.3-.175.6-.3l.4-3.2h5.5l.4 3.2q.325.125.613.3.287.175.562.375l2.975-1.25 2.75 4.75-2.575 1.95q.025.175.025.337v.675q0 .163-.05.338l2.575 1.95-2.75 4.75-2.95-1.25q-.275.2-.575.375-.3.175-.6.3l-.4 3.2Zm2.8-6.5q1.45 0 2.475-1.025Q15.55 13.45 15.55 12q0-1.45-1.025-2.475Q13.5 8.5 12.05 8.5q-1.475 0-2.488 1.025Q8.55 10.55 8.55 12q0 1.45 1.012 2.475Q10.575 15.5 12.05 15.5Z")
div(class="space")
script(type="module" src="../options/init.js")
script(type="module" src="./popup.js")

View File

@ -1,65 +0,0 @@
body {
width: 270px;
min-height: auto;
}
html,
body {
margin: 0;
}
.hide {
display: none !important;
}
.button {
display: flex;
margin: 0 auto;
justify-content: space-between;
}
.button svg {
width: 26px;
height: 26px;
}
.bottom-button {
width: 100%;
}
.space {
height: 10px;
}
input {
height: 23px;
width: 46px;
}
div.block label {
margin: 0;
font-size: 18px;
font-weight: bold;
max-width: 180px;
}
div.block label:hover {
cursor: pointer;
}
div.block div {
display: flex;
}
html.mobile body {
width: 100%;
}
html.mobile div.block label {
font-size: 24px;
}
html.mobile .button svg {
width: 30px;
height: 30px;
}

View File

@ -1,14 +0,0 @@
each _, service in services
div(class=`${service} block hide`)
a(class="title" href=services[service].url)
if services[service].imageType == 'svgMono'
img(class='dark' src=`/assets/images/${service}-icon.svg`)
img(class='light' src=`/assets/images/${service}-icon-light.svg`)
else
img(src=`/assets/images/${service}-icon.${services[service].imageType}`)
label=services[service].name
div
input(class=`${service}-enabled` type="checkbox" aria-label=`toggle ${services[service].name}`)
button(class=`${service}-change_instance title button` aria-label=`change instance for ${services[service].name}`)
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" preserveAspectRatio="xMinYMin meet" fill="currentColor")
path(d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z")

View File

@ -0,0 +1,114 @@
<script>
let browser = window.browser || window.chrome
import utils from "../../assets/javascripts/utils.js"
import { onDestroy } from "svelte"
import servicesHelper from "../../assets/javascripts/services.js"
import { onMount } from "svelte"
import Buttons from "./Buttons.svelte"
import { options, config, page } from "./stores"
let _options
const unsubscribeOptions = options.subscribe(val => {
if (val) {
_options = val
browser.storage.local.set({ options: val })
}
})
let _config
const unsubscribeConfig = config.subscribe(val => (_config = val))
onDestroy(() => {
unsubscribeOptions()
unsubscribeConfig()
})
onMount(async () => {
let opts = await utils.getOptions()
if (!opts) {
await servicesHelper.initDefaults()
opts = await utils.getOptions()
}
options.set(opts)
config.set(await utils.getConfig())
})
let _page
page.subscribe(val => (_page = val))
const dark = {
text: "#fff",
bgMain: "#121212",
bgSecondary: "#202020",
active: "#fbc117",
danger: "#f04141",
lightGrey: "#c3c3c3",
}
const light = {
text: "black",
bgMain: "white",
bgSecondary: "#e4e4e4",
active: "#fb9817",
danger: "#f04141",
lightGrey: "#c3c3c3",
}
let cssVariables
$: if (_options) {
if (_options.theme == "dark") {
cssVariables = dark
} else if (_options.theme == "light") {
cssVariables = light
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
cssVariables = dark
} else {
cssVariables = light
}
}
</script>
{#if _options && _config}
<div
class="main"
dir="auto"
style="
--text: {cssVariables.text};
--bg-main: {cssVariables.bgMain};
--bg-secondary: {cssVariables.bgSecondary};
--active: {cssVariables.active};
--danger: {cssVariables.danger};
--light-grey: {cssVariables.lightGrey};"
>
<Buttons />
</div>
{:else}
<p>Loading...</p>
{/if}
<style>
:global(html, body) {
width: 250px;
height: min-content;
min-height: auto;
margin: 0;
padding: 0;
box-sizing: border-box;
}
:global(body) {
margin-top: -20px;
}
div {
font-weight: bold;
height: 100%;
margin: 0;
padding: 10px;
padding-top: 20px;
font-family: "Inter";
font-size: 16px;
background-color: var(--bg-main);
color: var(--text);
}
</style>

View File

@ -0,0 +1,158 @@
<script>
let browser = window.browser || window.chrome
import Row from "./components/Row.svelte"
import Label from "../components/Label.svelte"
import CopyIcon from "../icons/CopyIcon.svelte"
import RedirectToOriginalIcon from "../icons/RedirectToOriginalIcon.svelte"
import RedirectIcon from "../icons/RedirectIcon.svelte"
import SwitchInstanceIcon from "../icons/SwitchInstanceIcon.svelte"
import SettingsIcon from "../icons/SettingsIcon.svelte"
import { options, config } from "./stores"
import ServiceIcon from "./components/ServiceIcon.svelte"
import { onDestroy } from "svelte"
import servicesHelper from "../../assets/javascripts/services"
import Checkbox from "../components/Checkbox.svelte"
let _options
let _config
const unsubscribeOptions = options.subscribe(val => (_options = val))
const unsubscribeConfig = config.subscribe(val => (_config = val))
onDestroy(() => {
unsubscribeOptions()
unsubscribeConfig()
})
let url
let switchInstance
let redirectToOriginal
let redirect
let currentService
browser.tabs.query({ active: true, currentWindow: true }, async tabs => {
if (tabs[0].url) {
url = new URL(tabs[0].url)
servicesHelper.switchInstance(url).then(r => (switchInstance = r))
servicesHelper.reverse(url).then(r => (redirectToOriginal = r))
servicesHelper.redirectAsync(url, "main_frame", null, true).then(r => (redirect = r))
currentService = await servicesHelper.computeService(url)
}
})
</script>
{#if redirect}
<Row class="row" on:click={() => browser.runtime.sendMessage("redirectTab")}>
<Label>Redirect</Label>
<RedirectIcon />
</Row>
{/if}
{#if switchInstance}
<Row class="row" on:click={async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url) })}>
<Label>Switch Instance</Label>
<SwitchInstanceIcon />
</Row>
{/if}
{#if redirectToOriginal}
<Row class="row" on:click={() => servicesHelper.copyRaw(url)}>
<Label>Copy Original</Label>
<CopyIcon />
</Row>
<Row class="row" on:click={() => browser.runtime.sendMessage("reverseTab")}>
<Label>Redirect To Original</Label>
<RedirectToOriginalIcon />
</Row>
{/if}
<hr />
{#if currentService}
<Row>
<div
style="display: flex;justify-content: space-between;align-items: center;"
class="row"
on:keydown={null}
on:click={() => window.open(browser.runtime.getURL(_config.services[currentService].url), "_blank")}
>
<ServiceIcon details={{ value: currentService, label: _config.services[currentService].name }} />
<Label>{_config.services[currentService].name}</Label>
</div>
<div style="display: flex;align-items: center;">
<Checkbox
style="margin-right:5px"
label="Enable"
checked={_options[currentService].enabled}
onChange={e => {
_options[currentService].enabled = e.target.checked
options.set(_options)
}}
/>
<SwitchInstanceIcon
class="row"
on:click={async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url, currentService) })}
/>
</div>
</Row>
{/if}
<hr />
{#each _options.popupServices as serviceKey}
{#if currentService !== serviceKey}
<Row>
<div
style="display: flex;align-items: center;"
class="row"
on:keydown={null}
on:click={() => window.open(browser.runtime.getURL(_config.services[serviceKey].url), "_blank")}
>
<ServiceIcon details={{ value: serviceKey, label: _config.services[serviceKey].name }} />
<Label>{_config.services[serviceKey].name}</Label>
</div>
<div style="display: flex;align-items: center;">
<Checkbox
style="margin-right:5px"
label="Enable"
checked={_options[serviceKey].enabled}
onChange={e => {
console.log(e.target.checked)
_options[serviceKey].enabled = e.target.checked
options.set(_options)
}}
/>
<SwitchInstanceIcon
class="row"
on:click={async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url, serviceKey) })}
/>
</div>
</Row>
{/if}
{/each}
<hr />
<Row class="row" on:click={() => window.open(browser.runtime.getURL("pages/options/index.html"), "_blank")}>
<Label>Settings</Label>
<SettingsIcon />
</Row>
<style>
:global(.row) {
transition: 0.1s;
}
:global(.row:hover) {
color: var(--active);
cursor: pointer;
}
:global(.row:active) {
transform: translateY(1px);
}
:global(img, svg) {
margin-right: 10px;
height: 26px;
width: 26px;
color: var(--text);
}
</style>

View File

@ -0,0 +1,11 @@
<script>
import Row from "../components/Row.svelte"
import Label from "../components/Label.svelte"
import CopyIcon from "../icons/CopyIcon.svelte"
export let label
</script>
<Row on:click>
<Label>{label}</Label>
<CopyIcon />
</Row>

View File

@ -0,0 +1,13 @@
<div {...$$props} on:click>
<slot></slot>
</div>
<style>
div {
justify-content: space-between;
display: flex;
align-items: center;
margin: 10px 0;
}
</style>

View File

@ -0,0 +1,40 @@
<script>
import { onDestroy } from "svelte"
export let details
import { config, options } from "../stores"
let _options
let _config
const unsubscribeOptions = options.subscribe(val => (_options = val))
const unsubscribeConfig = config.subscribe(val => (_config = val))
onDestroy(() => {
unsubscribeOptions()
unsubscribeConfig()
})
let theme
$: if (_options) {
if (_options.theme == "dark") {
theme = "dark"
} else if (_options.theme == "light") {
theme = "light"
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
theme = "dark"
} else {
theme = "light"
}
}
$: imageType = _config.services[details.value].imageType
</script>
{#if imageType}
{#if imageType == "svgMono"}
{#if theme == "dark"}
<img src={`/assets/images/${details.value}-icon-light.svg`} alt={details.label} />
{:else}
<img src={`/assets/images/${details.value}-icon.svg`} alt={details.label} />
{/if}
{:else}
<img src={`/assets/images/${details.value}-icon.${imageType}`} alt={details.label} />
{/if}
{/if}

View File

@ -0,0 +1,7 @@
import App from "./App.svelte"
const app = new App({
target: document.body,
})
export default app

View File

@ -0,0 +1,5 @@
import { writable } from "svelte/store"
export const options = writable(null)
export const config = writable(null)
export const page = writable("general")

View File

@ -1,12 +1,3 @@
body {
--text: #fff;
--bg-main: #121212;
--bg-secondary: #202020;
--active: #fbc117;
--danger: #f04141;
--light-grey: #c3c3c3;
}
@font-face {
font-family: "Inter";
src: url("Inter-VariableFont_slnt,wght.ttf");
@ -21,359 +12,7 @@ body {
font-style: normal;
}
body {
margin: auto;
padding: 0;
font-family: "Inter";
font-size: 16px;
background-color: var(--bg-main);
color: var(--text);
}
body * {
font-family: "Inter";
}
body.rtl {
font-family: "Vazirmatn";
}
body.rtl * {
font-family: "Vazirmatn";
}
div.block input[type="checkbox"] {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
}
.title {
display: flex;
align-items: center;
text-decoration: none;
width: min-content;
color: var(--text);
transition: 0.1s;
}
.title:hover {
opacity: 1 !important;
}
.title:hover a {
color: var(--active);
}
img,
svg {
margin-right: 10px;
height: 26px;
width: 26px;
color: var(--text);
}
body.rtl img,
body.rtl svg {
margin-right: 0px;
margin-left: 10px;
}
input[type="url"],
input[type="text"],
select {
font-weight: bold;
box-sizing: border-box;
border-style: solid;
border-color: #767676;
color: var(--text);
font-size: 16px;
padding: 8px;
background-color: var(--bg-secondary);
border: none;
margin: 0;
max-width: 500px;
border-radius: 3px;
}
input[type="url"],
input[type="text"] {
width: 400px;
cursor: text;
}
input:invalid {
color: var(--danger);
}
.button svg {
height: 18px;
width: 18px;
}
section.block-option {
width: 750px;
margin: 0 50px;
}
section.block-option h2 {
margin: 0;
}
body.option {
display: flex;
padding: 40px;
width: 1160px;
}
section.links {
display: flex;
flex-wrap: wrap;
flex-direction: column;
width: 350px;
max-height: 1030px;
}
section.links div {
margin: 10px;
width: max-content;
}
a {
text-decoration: none;
color: var(--text);
transition: 0.1s;
}
a:hover {
color: var(--active);
}
section.links a {
display: flex;
align-items: center;
font-size: 18px;
text-decoration: none;
color: white;
transition: 0.1s;
}
section.links a:hover,
section.links .selected {
opacity: 1 !important;
}
section.links .selected a {
color: var(--active);
}
::placeholder {
color: var(--text);
opacity: 0.7;
}
hr {
height: 2px;
margin: 0 15px;
background-color: rgb(77, 77, 77);
border: none;
}
div.block {
padding: 0 15px;
justify-content: space-between;
display: flex;
align-items: center;
margin-top: 10px;
margin-bottom: 10px;
}
div.block-option {
margin: 30px 0;
}
div.block-option label {
margin-right: 5px;
width: 80%;
min-width: 150px;
font-size: 18px;
}
div.block-option h1 {
margin: 0;
font-size: 28px;
color: var(--text);
}
div.block-option div {
text-align: center;
}
div.block input[type="checkbox"] {
width: 46px;
height: 24px;
background-color: var(--light-grey);
border-radius: 50px;
transition: 0.4s;
cursor: pointer;
}
div.block input[type="checkbox"]:checked {
background-color: var(--active);
}
div.block input[type="checkbox"]::before {
content: "";
display: inline-block;
width: 18px;
height: 18px;
box-sizing: border-box;
position: relative;
top: 2.5px;
left: 3.5px;
background-color: white;
border-radius: 50%;
transition: 0.3s;
}
body.rtl div.block input[type="checkbox"]::before {
left: auto;
right: 4px;
}
div.block input[type="checkbox"]:checked::before {
left: 24px;
}
body.rtl div.block input[type="checkbox"]:checked::before {
left: auto;
right: 24px;
}
div.buttons {
display: flex;
margin: 0 15px;
margin-bottom: 15px;
margin-top: 15px;
flex-wrap: wrap;
align-items: center;
justify-content: start;
}
.button {
color: var(--text);
font-size: 16px;
font-weight: bold;
text-decoration: none;
cursor: pointer;
transition-duration: 0.1s;
}
.button:hover {
color: var(--active);
}
.button svg {
width: auto;
height: auto;
padding: 0;
margin-right: 5px;
}
.button:hover svg {
color: var(--active);
}
.button-inline {
display: inline-flex;
align-items: center;
margin: 7.5px 0;
background-color: var(--bg-secondary);
border-radius: 5px;
padding: 10px;
}
.button:active {
transform: translateY(1px);
}
button svg {
color: var(--text);
}
div.checklist div {
justify-content: space-between;
margin: 5px 15px;
padding: 10px 0;
word-wrap: break-word;
display: flex;
}
div.checklist a {
text-decoration: none;
color: var(--text);
}
div.checklist a:hover {
text-decoration: underline;
}
div.custom-checklist x a {
color: var(--active);
}
button.add {
background-color: transparent;
border: none;
padding: 0;
margin: 0;
text-decoration: none;
display: inline-block;
cursor: pointer;
}
body.light-theme {
--text: black;
--bg-main: white;
--bg-secondary: #e4e4e4;
--active: #fb9817;
}
body.light-theme select {
border: 1px solid black;
}
body.light-theme a {
color: black;
}
body.light-theme a:hover {
color: var(--active);
}
button {
background-color: transparent;
color: var(--text);
border: none;
text-decoration: none;
display: inline-block;
cursor: pointer;
border-radius: 5px;
}
body div section {
display: none;
}
select:disabled {
opacity: 0.6;
cursor: not-allowed;
}
input:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/*
@media (max-width: 1250px) {
body.option {
@ -446,4 +85,4 @@ html.mobile section.links {
html.mobile section.block-option {
width: 100%;
}
} */