diff options
65 files changed, 1231 insertions, 1297 deletions
diff --git a/.gitignore b/.gitignore index 7ca34ebb..f9768f05 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file +src/pages/options/build +src/pages/popup/build \ No newline at end of file diff --git a/package.json b/package.json index 234dd5e1..2a79b660 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,17 @@ "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", "nightly": "web-ext run --firefox=/home/esmail/software/firefox_nightly/firefox", - "android": "web-ext run -t firefox-android --adb-device emulator-5554 --firefox-apk org.mozilla.fenix", + "start_ar": "web-ext run --firefox=/home/esmail/software/firefox_ar/firefox", + "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 +26,7 @@ }, "homepage": "https://libredirect.github.io", "devDependencies": { - "prettier": "3.3.3", - "pug-cli": "^1.0.0-alpha6", - "web-ext": "^7.2.0", - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-node-resolve": "^15.0.0", - "@rollup/plugin-terser": "^0.4.0", - "rollup": "^3.15.0", - "rollup-plugin-css-only": "^4.3.0", - "rollup-plugin-svelte": "^7.1.2", - "svelte": "^3.55.0" + "prettier": "3.3.3" }, "webExt": { "sourceDir": "./src/", @@ -44,5 +36,17 @@ "build": { "overwriteDest": true } + }, + "dependencies": { + "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" } } diff --git a/rollup.config.js b/rollup.config.js index 71222de8..5a2ce362 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -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, diff --git a/src/assets/images/libredirect.svg b/src/assets/images/libredirect.svg index ad616dd3..a9d63d95 100644 --- a/src/assets/images/libredirect.svg +++ b/src/assets/images/libredirect.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 333.369 333.369"><g><path d="M166.684 0c-3.524 0-7.047 1.35-9.748 4.051L4.051 156.935a13.76 13.76 0 0 0 0 19.5l152.885 152.883a13.757 13.757 0 0 0 19.498 0l152.884-152.884a13.76 13.76 0 0 0 0-19.499L176.434 4.051A13.75 13.75 0 0 0 166.684 0" style="fill:#000;fill-opacity:1;stroke-width:10.6446;stroke-linejoin:bevel;paint-order:stroke markers fill;stop-color:#000"/><path d="M166.684 0c-3.524 0-7.047 1.35-9.748 4.051L4.051 156.935a13.76 13.76 0 0 0 0 19.5l152.885 152.883a13.757 13.757 0 0 0 19.498 0l152.884-152.884a13.76 13.76 0 0 0 0-19.499L176.434 4.051A13.75 13.75 0 0 0 166.684 0m0 10.72a12.86 12.86 0 0 1 9.123 3.79L318.86 157.562a12.873 12.873 0 0 1 0 18.245L175.807 318.86a12.873 12.873 0 0 1-18.245 0L14.51 175.807a12.873 12.873 0 0 1 0-18.245L157.562 14.51a12.86 12.86 0 0 1 9.122-3.79" style="fill:#fbc118;fill-opacity:1;stroke-width:10.6446;stroke-linejoin:bevel;paint-order:stroke markers fill;stop-color:#000"/><rect width="211.979" height="211.979" x="-105.99" y="129.738" ry="11.989" style="fill:#fbc117;fill-opacity:1;stroke-width:9.25578;stroke-linejoin:bevel;paint-order:stroke markers fill;stop-color:#000" transform="rotate(-45)"/><path d="M184.948 150.313c-47.943 20.638-46.951 86.743-46.951 86.743h-33.492s-.437-96.715 73.158-116.434c-6.913-13.854-10.362-19.427-5.933-21.62 5.935-2.94 68.022 11.716 70.346 20.393 2.286 8.528-46.827 53.143-53.656 53.143-5.852 0-4.229-7.023-3.472-22.225z" style="fill:#000;fill-opacity:1;stroke-width:11.7733;stroke-linejoin:bevel;paint-order:stroke markers fill;stop-color:#000"/></g></svg> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 333.369 333.369"><path d="M166.684 0a13.74 13.74 0 0 0-9.748 4.051L4.051 156.935a13.76 13.76 0 0 0 0 19.5l152.885 152.883a13.757 13.757 0 0 0 19.498 0l152.884-152.884a13.76 13.76 0 0 0 0-19.499L176.434 4.051A13.75 13.75 0 0 0 166.684 0"/><path fill="#fbc118" d="M166.684 0a13.74 13.74 0 0 0-9.748 4.051L4.051 156.935a13.76 13.76 0 0 0 0 19.5l152.885 152.883a13.757 13.757 0 0 0 19.498 0l152.884-152.884a13.76 13.76 0 0 0 0-19.499L176.434 4.051A13.75 13.75 0 0 0 166.684 0m0 10.72a12.86 12.86 0 0 1 9.123 3.79L318.86 157.562a12.873 12.873 0 0 1 0 18.245L175.807 318.86a12.873 12.873 0 0 1-18.245 0L14.51 175.807a12.873 12.873 0 0 1 0-18.245L157.562 14.51a12.86 12.86 0 0 1 9.122-3.79"/><rect width="211.979" height="211.979" x="-105.99" y="129.738" fill="#fbc117" ry="11.989" transform="rotate(-45)"/><path d="M184.948 150.313c-47.943 20.638-46.951 86.743-46.951 86.743h-33.492s-.437-96.715 73.158-116.434c-6.913-13.854-10.362-19.427-5.933-21.62 5.935-2.94 68.022 11.716 70.346 20.393 2.286 8.528-46.827 53.143-53.656 53.143-5.852 0-4.229-7.023-3.472-22.225"/></svg> \ No newline at end of file diff --git a/src/assets/javascripts/localise.js b/src/assets/javascripts/localise.js deleted file mode 100644 index d26d07d4..00000000 --- a/src/assets/javascripts/localise.js +++ /dev/null @@ -1,34 +0,0 @@ -window.browser = window.browser || window.chrome - -function localisePage() { - /** - * @param {string} tag - */ - function getMessage(tag) { - return tag.replace(/__MSG_(\w+)__/g, (_match, v1) => { - return v1 ? browser.i18n.getMessage(v1) : null - }) - } - - const elements = document.querySelectorAll("[data-localise]") - for (let i in elements) - if (elements.hasOwnProperty(i)) { - const obj = elements[i] - const tag = obj.getAttribute("data-localise").toString() - const msg = getMessage(tag) - if (msg && msg !== tag) obj.textContent = msg - } - - const placeholders = document.querySelectorAll("[data-localise-placeholder]") - for (let i in placeholders) - if (placeholders.hasOwnProperty(i)) { - const obj = placeholders[i] - const tag = obj.getAttribute("data-localise-placeholder").toString() - const msg = getMessage(tag) - if (msg && msg !== tag) obj.placeholder = msg - } -} - -export default { - localisePage, -} diff --git a/src/assets/javascripts/utils.js b/src/assets/javascripts/utils.js index 439826dd..18168e90 100644 --- a/src/assets/javascripts/utils.js +++ b/src/assets/javascripts/utils.js @@ -21,13 +21,6 @@ function getNextInstance(currentInstanceUrl, instances) { } /** - * @param {string} str - */ -function camelCase(str) { - return str.charAt(0).toUpperCase() + str.slice(1) -} - -/** * @param {URL} url */ function protocolHost(url) { @@ -178,7 +171,6 @@ export default { protocolHost, getList, getBlacklist, - camelCase, getConfig, getOptions, getPingCache, diff --git a/src/config.json b/src/config.json index 3f58ea95..9728cdc3 100644 --- a/src/config.json +++ b/src/config.json @@ -917,14 +917,15 @@ "simplyTranslate": { "name": "SimplyTranslate", "instanceList": true, - "url": "https://git.sr.ht/~metalune/simplytranslate_web", + "url": "https://codeberg.org/ManeraKai/simplytranslate", "localhost": true }, "mozhi": { "name": "Mozhi", "instanceList": true, "url": "https://codeberg.org/aryak/mozhi", - "localhost": false + "localhost": false, + "imageType": "svg" }, "libreTranslate": { "name": "LibreTranslate", diff --git a/src/manifest.json b/src/manifest.json index 1f36e7c7..880268bb 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -29,7 +29,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", @@ -48,7 +48,7 @@ "search_provider": { "name": "__MSG_extensionName__", "keyword": "@libredirect", - "favicon_url": "https://raw.githubusercontent.com/libredirect/libredirect/master/src/assets/images/libredirect-16.png", + "favicon_url": "https://raw.githubusercontent.com/libredirect/browser_extension/master/src/assets/images/libredirect.svg", "search_url": "https://search.libredirect.invalid/?q={searchTerms}", "encoding": "UTF-8", "is_default": false diff --git a/src/pages/src/components/Button.svelte b/src/pages/components/Button.svelte index 3405c2ea..8836b47e 100644 --- a/src/pages/src/components/Button.svelte +++ b/src/pages/components/Button.svelte @@ -1,4 +1,4 @@ -<button on:click {...$$props}> +<button {...$$restProps} on:click {...$$props}> <slot></slot> </button> diff --git a/src/pages/src/components/Checkbox.svelte b/src/pages/components/Checkbox.svelte index f5245045..9ba9c56c 100644 --- a/src/pages/src/components/Checkbox.svelte +++ b/src/pages/components/Checkbox.svelte @@ -1,9 +1,10 @@ <script> export let checked export let onChange + console.log(document.body.dir) </script> -<input bind:checked on:change={onChange} type="checkbox" /> +<input class={document.body.dir} {...$$restProps} bind:checked on:change={onChange} type="checkbox" /> <style> input[type="checkbox"] { @@ -40,13 +41,13 @@ left: 24px; } - /* body.rtl div.block input[type="checkbox"]::before { - left: auto; - right: 4px; - } */ + input[type="checkbox"].rtl::before { + left: auto; + right: 3.5px; + } - /* body.rtl div.block input[type="checkbox"]:checked::before { - left: auto; - right: 24px; - } */ + input[type="checkbox"].rtl:checked::before { + left: auto; + right: 24px; + } </style> diff --git a/src/pages/src/components/Input.svelte b/src/pages/components/Input.svelte index d963233c..59e584db 100644 --- a/src/pages/src/components/Input.svelte +++ b/src/pages/components/Input.svelte @@ -3,7 +3,7 @@ </script> <input - {...$$props} + {...$$restProps} bind:value on:blur on:change @@ -38,4 +38,9 @@ input:focus { outline-color: var(--active); } + @media (max-width: 715px) { + input { + width: 200px; + } + } </style> diff --git a/src/pages/src/components/Label.svelte b/src/pages/components/Label.svelte index 39930cd1..39930cd1 100644 --- a/src/pages/src/components/Label.svelte +++ b/src/pages/components/Label.svelte diff --git a/src/pages/src/components/Row.svelte b/src/pages/components/Row.svelte index 4f23cffa..09246d98 100644 --- a/src/pages/src/components/Row.svelte +++ b/src/pages/components/Row.svelte @@ -1,4 +1,4 @@ -<div {...$$props}> +<div {...$$restProps} on:click> <slot></slot> </div> diff --git a/src/pages/src/components/Select.svelte b/src/pages/components/Select.svelte index a0939d1f..7829c53e 100644 --- a/src/pages/src/components/Select.svelte +++ b/src/pages/components/Select.svelte @@ -5,7 +5,7 @@ export let ariaLabel </script> -<select bind:value={value} on:change={onChange} aria-label={ariaLabel} on:change on:contextmenu on:input> +<select bind:value on:change={onChange} aria-label={ariaLabel} on:change on:contextmenu on:input> {#each values as option} <option value={option.value}>{option.name}</option> {/each} diff --git a/src/pages/stylesheets/Inter-VariableFont_slnt,wght.ttf b/src/pages/fonts/Inter-VariableFont_slnt,wght.ttf index 969a990f..969a990f 100644 --- a/src/pages/stylesheets/Inter-VariableFont_slnt,wght.ttf +++ b/src/pages/fonts/Inter-VariableFont_slnt,wght.ttf Binary files differdiff --git a/src/pages/stylesheets/Vazirmatn-VariableFont_wght.ttf b/src/pages/fonts/Vazirmatn-VariableFont_wght.ttf index f4b97c01..f4b97c01 100644 --- a/src/pages/stylesheets/Vazirmatn-VariableFont_wght.ttf +++ b/src/pages/fonts/Vazirmatn-VariableFont_wght.ttf Binary files differdiff --git a/src/pages/fonts/styles.css b/src/pages/fonts/styles.css new file mode 100644 index 00000000..754543b1 --- /dev/null +++ b/src/pages/fonts/styles.css @@ -0,0 +1,13 @@ +@font-face { + font-family: "Inter"; + src: url("Inter-VariableFont_slnt,wght.ttf"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Vazirmatn"; + src: url("Vazirmatn-VariableFont_wght.ttf"); + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/src/pages/src/icons/AboutIcon.svelte b/src/pages/icons/AboutIcon.svelte index e113dd68..e113dd68 100644 --- a/src/pages/src/icons/AboutIcon.svelte +++ b/src/pages/icons/AboutIcon.svelte diff --git a/src/pages/src/icons/AddIcon.svelte b/src/pages/icons/AddIcon.svelte index ab26f078..ab26f078 100644 --- a/src/pages/src/icons/AddIcon.svelte +++ b/src/pages/icons/AddIcon.svelte diff --git a/src/pages/src/icons/CloseIcon.svelte b/src/pages/icons/CloseIcon.svelte index ddfb29cb..ddfb29cb 100644 --- a/src/pages/src/icons/CloseIcon.svelte +++ b/src/pages/icons/CloseIcon.svelte diff --git a/src/pages/icons/CopyIcon.svelte b/src/pages/icons/CopyIcon.svelte new file mode 100644 index 00000000..37c13f98 --- /dev/null +++ b/src/pages/icons/CopyIcon.svelte @@ -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> diff --git a/src/pages/src/icons/ExportIcon.svelte b/src/pages/icons/ExportIcon.svelte index 196726a8..d155e5c5 100644 --- a/src/pages/src/icons/ExportIcon.svelte +++ b/src/pages/icons/ExportIcon.svelte @@ -1,4 +1,11 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"> +<svg + {...$$restProps} + xmlns="http://www.w3.org/2000/svg" + height="24px" + viewBox="0 0 24 24" + width="24px" + fill="currentColor" +> <path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" /> diff --git a/src/pages/src/icons/GeneralIcon.svelte b/src/pages/icons/GeneralIcon.svelte index b9429021..b9429021 100644 --- a/src/pages/src/icons/GeneralIcon.svelte +++ b/src/pages/icons/GeneralIcon.svelte diff --git a/src/pages/icons/ImportIcon.svelte b/src/pages/icons/ImportIcon.svelte new file mode 100644 index 00000000..f64d0ff6 --- /dev/null +++ b/src/pages/icons/ImportIcon.svelte @@ -0,0 +1,12 @@ +<svg + {...$$restProps} + xmlns="http://www.w3.org/2000/svg" + height="24px" + viewBox="0 0 24 24" + width="24px" + fill="currentColor" +> + <path + d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" + /> +</svg> diff --git a/src/pages/src/icons/PingIcon.svelte b/src/pages/icons/PingIcon.svelte index 8fcfe27b..34c4a37d 100644 --- a/src/pages/src/icons/PingIcon.svelte +++ b/src/pages/icons/PingIcon.svelte @@ -1,4 +1,11 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 24 24" width="20px" fill="currentColor"> +<svg + {...$$restProps} + xmlns="http://www.w3.org/2000/svg" + height="20px" + viewBox="0 0 24 24" + width="20px" + fill="currentColor" +> <path d="M10.45 15.5q.6.6 1.55.587.95-.012 1.4-.687L19 7l-8.4 5.6q-.675.45-.712 1.375-.038.925.562 1.525ZM12 4q1.475 0 2.838.412Q16.2 4.825 17.4 5.65l-1.9 1.2q-.825-.425-1.712-.637Q12.9 6 12 6 8.675 6 6.338 8.337 4 10.675 4 14q0 1.05.287 2.075Q4.575 17.1 5.1 18h13.8q.575-.95.838-1.975Q20 15 20 13.9q0-.9-.212-1.75-.213-.85-.638-1.65l1.2-1.9q.75 1.175 1.188 2.5.437 1.325.462 2.75.025 1.425-.325 2.725-.35 1.3-1.025 2.475-.275.45-.75.7-.475.25-1 .25H5.1q-.525 0-1-.25t-.75-.7q-.65-1.125-1-2.387Q2 15.4 2 14q0-2.075.788-3.888.787-1.812 2.15-3.175Q6.3 5.575 8.125 4.787 9.95 4 12 4Zm.175 7.825Z" /></svg diff --git a/src/pages/icons/RedirectIcon.svelte b/src/pages/icons/RedirectIcon.svelte new file mode 100644 index 00000000..9392762a --- /dev/null +++ b/src/pages/icons/RedirectIcon.svelte @@ -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> diff --git a/src/pages/icons/RedirectToOriginalIcon.svelte b/src/pages/icons/RedirectToOriginalIcon.svelte new file mode 100644 index 00000000..aad5c48e --- /dev/null +++ b/src/pages/icons/RedirectToOriginalIcon.svelte @@ -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> diff --git a/src/pages/src/icons/ResetIcon.svelte b/src/pages/icons/ResetIcon.svelte index 0900aef8..6daf57e6 100644 --- a/src/pages/src/icons/ResetIcon.svelte +++ b/src/pages/icons/ResetIcon.svelte @@ -5,6 +5,7 @@ viewBox="0 0 24 24" width="24px" fill="currentColor" + {...$$restProps} > <path d="M12,5V2L8,6l4,4V7c3.31,0,6,2.69,6,6c0,2.97-2.17,5.43-5,5.91v2.02c3.95-0.49,7-3.85,7-7.93C20,8.58,16.42,5,12,5z" diff --git a/src/pages/src/icons/ServicesIcon.svelte b/src/pages/icons/ServicesIcon.svelte index ec24259b..ec24259b 100644 --- a/src/pages/src/icons/ServicesIcon.svelte +++ b/src/pages/icons/ServicesIcon.svelte diff --git a/src/pages/icons/SettingsIcon.svelte b/src/pages/icons/SettingsIcon.svelte new file mode 100644 index 00000000..f47d078a --- /dev/null +++ b/src/pages/icons/SettingsIcon.svelte @@ -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> diff --git a/src/pages/icons/SwitchInstanceIcon.svelte b/src/pages/icons/SwitchInstanceIcon.svelte new file mode 100644 index 00000000..6a1f96ac --- /dev/null +++ b/src/pages/icons/SwitchInstanceIcon.svelte @@ -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> diff --git a/src/pages/options/index.html b/src/pages/options/index.html new file mode 100644 index 00000000..b197d4a7 --- /dev/null +++ b/src/pages/options/index.html @@ -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='../fonts/styles.css'> + <script defer src='build/bundle.js'></script> +</head> + +<body> +</body> + +</html> \ No newline at end of file diff --git a/src/pages/options/init.js b/src/pages/options/init.js deleted file mode 100644 index 07da1859..00000000 --- a/src/pages/options/init.js +++ /dev/null @@ -1,51 +0,0 @@ -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) diff --git a/src/pages/options_src/App.svelte b/src/pages/options_src/App.svelte new file mode 100644 index 00000000..dfafe1f0 --- /dev/null +++ b/src/pages/options_src/App.svelte @@ -0,0 +1,139 @@ +<script> + const browser = window.browser || window.chrome + + import General from "./General/General.svelte" + import utils from "../../assets/javascripts/utils.js" + import { onDestroy } from "svelte" + import servicesHelper from "../../assets/javascripts/services.js" + import { onMount } from "svelte" + import Sidebar from "./Sidebar.svelte" + import { options, config, page } from "./stores" + import Services from "./Services/Services.svelte" + + 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 + } + } + + const dir = ["ar", "iw", "ku", "fa", "ur"].includes(browser.i18n.getUILanguage()) ? "rtl" : "ltr" + document.body.dir = dir +</script> + +{#if _options && _config} + <div + class={dir} + {dir} + style=" + --text: {cssVariables.text}; + --bg-main: {cssVariables.bgMain}; + --bg-secondary: {cssVariables.bgSecondary}; + --active: {cssVariables.active}; + --danger: {cssVariables.danger}; + --light-grey: {cssVariables.lightGrey};" + > + <Sidebar /> + {#if _page == "general"} + <General /> + {:else if _page == "services"} + <Services /> + {/if} + </div> +{:else} + <p>Loading...</p> +{/if} + +<style> + :global(body) { + width: 100vw; + height: 100vh; + margin: 0; + padding: 0; + } + + div { + height: 100%; + display: grid; + grid-template-columns: min-content 800px; + margin: 0; + padding-top: 50px; + justify-content: center; + font-family: "Inter"; + box-sizing: border-box; + font-size: 16px; + background-color: var(--bg-main); + color: var(--text); + overflow: scroll; + } + + @media (max-width: 1250px) { + div { + grid-template-columns: auto; + grid-template-rows: min-content auto; + padding-left: 5vw; + padding-right: 5vw; + } + } + + @media (max-width: 715px) { + div { + font-size: 14px; + grid-template-columns: auto; + grid-template-rows: min-content auto; + padding-left: 5vw; + padding-right: 5vw; + } + } +</style> diff --git a/src/pages/src/General/Exceptions.svelte b/src/pages/options_src/General/Exceptions.svelte index e43afaf6..7315877d 100644 --- a/src/pages/src/General/Exceptions.svelte +++ b/src/pages/options_src/General/Exceptions.svelte @@ -1,10 +1,12 @@ <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" + const browser = window.browser || window.chrome + + 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" @@ -54,10 +56,10 @@ } </script> -<div class="block block-option"> - <Row> - <Label>Excluded from redirecting</Label> - </Row> +<Row> + <Label>{browser.i18n.getMessage("excludeFromRedirecting") || "Excluded from redirecting"}</Label> +</Row> +<div dir="ltr"> <Row> <div> <Input diff --git a/src/pages/options_src/General/General.svelte b/src/pages/options_src/General/General.svelte new file mode 100644 index 00000000..37c38a0a --- /dev/null +++ b/src/pages/options_src/General/General.svelte @@ -0,0 +1,79 @@ +<script> + const browser = window.browser || window.chrome + + import Exceptions from "./Exceptions.svelte" + import SettingsButtons from "./SettingsButtons.svelte" + import { options } from "../stores" + import { onDestroy } from "svelte" + import Row from "../../components/Row.svelte" + import Label from "../../components/Label.svelte" + import Select from "../../components/Select.svelte" + import Checkbox from "../../components/Checkbox.svelte" + + let _options + const unsubscribe = options.subscribe(val => (_options = val)) + onDestroy(unsubscribe) + + let bookmarksPermission + browser.permissions.contains({ permissions: ["bookmarks"] }, r => (bookmarksPermission = r)) + $: if (bookmarksPermission) { + browser.permissions.request({ permissions: ["bookmarks"] }, r => (bookmarksPermission = r)) + } else { + browser.permissions.remove({ permissions: ["bookmarks"] }) + bookmarksPermission = false + } +</script> + +<div> + <Row> + <Label>{browser.i18n.getMessage("theme") || "Theme"}</Label> + <Select + values={[ + { value: "detect", name: browser.i18n.getMessage("auto") || "Auto" }, + { value: "light", name: browser.i18n.getMessage("light") || "Light" }, + { value: "dark", name: browser.i18n.getMessage("dark") || "Dark" }, + ]} + value={_options.theme} + onChange={e => { + _options.theme = e.target.options[e.target.options.selectedIndex].value + options.set(_options) + }} + /> + </Row> + + <Row> + <Label>{browser.i18n.getMessage("fetchPublicInstances") || "Fetch public instances"}</Label> + <Select + value={_options.fetchInstances} + values={[ + { value: "github", name: "GitHub" }, + { value: "codeberg", name: "Codeberg" }, + { value: "disable", name: browser.i18n.getMessage("disable") || "Disable" }, + ]} + onChange={e => { + _options.fetchInstances = e.target.options[e.target.options.selectedIndex].value + options.set(_options) + }} + /> + </Row> + + <Row> + <Label>{browser.i18n.getMessage("redirectOnlyInIncognito") || "Redirect Only in Incognito"}</Label> + <Checkbox + checked={_options.redirectOnlyInIncognito} + onChange={e => { + _options.redirectOnlyInIncognito = e.target.checked + options.set(_options) + }} + /> + </Row> + + <Row> + <Label>{browser.i18n.getMessage("bookmarksMenu") || "Bookmarks menu"}</Label> + <Checkbox bind:checked={bookmarksPermission} /> + </Row> + + <Exceptions /> + + <SettingsButtons /> +</div> diff --git a/src/pages/src/General/SettingsButtons.svelte b/src/pages/options_src/General/SettingsButtons.svelte index 89d5e95d..2f574199 100644 --- a/src/pages/src/General/SettingsButtons.svelte +++ b/src/pages/options_src/General/SettingsButtons.svelte @@ -1,11 +1,11 @@ <script> - let browser = window.browser || window.chrome + const 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" @@ -14,24 +14,18 @@ const unsubscribe = options.subscribe(val => (_options = val)) onDestroy(unsubscribe) - let disableButtons = false - let importSettingsInput let importSettingsFiles $: if (importSettingsFiles) { - disableButtons = true const reader = new FileReader() reader.readAsText(importSettingsFiles[0]) reader.onload = async () => { const data = JSON.parse(reader.result) if ("theme" in data && data.version == browser.runtime.getManifest().version) { browser.storage.local.clear(async () => { - console.log("clearing") options.set(data) - disableButtons = false }) } else { - console.log("incompatible settings") alert("Incompatible settings") } } @@ -42,26 +36,21 @@ } async function exportSettings() { - disableButtons = true _options.version = browser.runtime.getManifest().version const resultString = JSON.stringify(_options, null, " ") const anchor = document.createElement("a") anchor.href = "data:application/json;base64," + btoa(resultString) anchor.download = `libredirect-settings-v${_options.version}.json` anchor.click() - disableButtons = false } async function exportSettingsSync() { - disableButtons = true _options.version = browser.runtime.getManifest().version await servicesHelper.initDefaults() browser.storage.sync.set({ options: _options }) - disableButtons = false } async function importSettingsSync() { - disableButtons = true browser.storage.sync.get({ options }, r => { const optionsSync = r.options if (optionsSync.version == browser.runtime.getManifest().version) { @@ -69,24 +58,21 @@ } else { alert("Error") } - disableButtons = false }) } async function resetSettings() { - disableButtons = true browser.storage.local.clear(async () => { await servicesHelper.initDefaults() options.set(await utils.getOptions()) - disableButtons = false }) } </script> <div class="buttons"> - <Button on:click={() => importSettingsInput.click()} disabled={disableButtons}> - <ImportIcon /> - <x data-localise="__MSG_importSettings__">Import Settings</x> + <Button on:click={() => importSettingsInput.click()}> + <ImportIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("importSettings") || "Import Settings"} </Button> <input type="file" @@ -96,23 +82,34 @@ bind:files={importSettingsFiles} /> - <Button on:click={exportSettings} disabled={disableButtons}> - <ExportIcon /> - <x data-localise="__MSG_exportSettings__">Export Settings</x> + <Button on:click={exportSettings}> + <ExportIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("exportSettings") || "Export Settings"} </Button> - <Button on:click={exportSettingsSync} disabled={disableButtons}> - <ExportIcon /> - <x>Export Settings to Sync</x> + <Button on:click={exportSettingsSync}> + <ExportIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("exportSettingsToSync") || "Export Settings to Sync"} </Button> - <Button on:click={importSettingsSync} disabled={disableButtons}> - <ImportIcon /> - <x>Import Settings from Sync</x> + <Button on:click={importSettingsSync}> + <ImportIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("importSettingsFromSync") || "Import Settings from Sync"} </Button> - <Button on:click={resetSettings} disabled={disableButtons}> - <ResetIcon /> - <x>Reset Settings</x> + <Button on:click={resetSettings}> + <ResetIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("resetSettings") || "Reset Settings"} </Button> </div> + +<style> + :global(.margin) { + margin-right: 10px; + margin-left: 0; + } + :global(.margin_rtl) { + margin-right: 0; + margin-left: 10px; + } +</style> diff --git a/src/pages/options_src/Services/FrontendIcon.svelte b/src/pages/options_src/Services/FrontendIcon.svelte new file mode 100644 index 00000000..24942fd6 --- /dev/null +++ b/src/pages/options_src/Services/FrontendIcon.svelte @@ -0,0 +1,43 @@ +<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" + } + } + + export let selectedService + + $: imageType = _config.services[selectedService].frontends[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} diff --git a/src/pages/src/Services/Instances.svelte b/src/pages/options_src/Services/Instances.svelte index 3c9b1ccf..862bbf7e 100644 --- a/src/pages/src/Services/Instances.svelte +++ b/src/pages/options_src/Services/Instances.svelte @@ -1,18 +1,19 @@ <script> - let browser = window.browser || window.chrome + const 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" export let selectedService + export let selectedFrontend let _options let _config @@ -27,17 +28,16 @@ let blacklist let redirects - $: serviceOptions = _options[selectedService] $: serviceConf = _config.services[selectedService] let allInstances = [] $: { allInstances = [] - if (_options[serviceOptions.frontend]) allInstances.push(..._options[serviceOptions.frontend]) - if (redirects && redirects[serviceOptions.frontend]) { - for (const network in redirects[serviceOptions.frontend]) { - allInstances.push(...redirects[serviceOptions.frontend][network]) + if (_options[selectedFrontend]) allInstances.push(..._options[selectedFrontend]) + if (redirects && redirects[selectedFrontend]) { + for (const network in redirects[selectedFrontend]) { + allInstances.push(...redirects[selectedFrontend][network]) } } } @@ -48,12 +48,12 @@ } function isCustomInstance(instance) { - if (redirects[serviceOptions.frontend]) { - for (const network in redirects[serviceOptions.frontend]) { - if (redirects[serviceOptions.frontend][network].includes(instance)) return true + if (redirects[selectedFrontend]) { + for (const network in redirects[selectedFrontend]) { + if (redirects[selectedFrontend][network].includes(instance)) return false } } - return false + return true } async function pingInstances() { @@ -62,10 +62,10 @@ console.log("pinging...", instance) pingCache[instance] = { color: "lightblue", value: "pinging..." } const time = await utils.ping(instance) - pingCache[instance] = processTime(time) + pingCache[instance] = colorTime(time) } } - function processTime(time) { + function colorTime(time) { let value let color if (time < 5000) { @@ -92,44 +92,42 @@ let addInstanceValue function addInstance() { const instance = utils.protocolHost(new URL(addInstanceValue)) - if (!_options[serviceOptions.frontend].includes(instance)) { - _options[serviceOptions.frontend].push(instance) + if (!_options[selectedFrontend].includes(instance)) { + _options[selectedFrontend].push(instance) addInstanceValue = "" options.set(_options) } } </script> -{#if serviceConf.frontends[serviceOptions.frontend].instanceList && redirects && blacklist} +{#if serviceConf.frontends[selectedFrontend].instanceList && redirects && blacklist} <hr /> - <div dir="ltr"> - <div class="ping"> - <Button on:click={pingInstances}> - <PingIcon /> - Ping Instances - </Button> - </div> - <Row> - <Label>Add your favorite instances</Label> - </Row> + <div class="ping"> + <Button on:click={pingInstances}> + <PingIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("pingInstances") || "Ping Instances"} + </Button> + </div> + <Row> + <Label>{browser.i18n.getMessage("addYourFavoriteInstances") || "Add your favorite instances"}</Label> + </Row> + <div dir="ltr"> <Row> <Input bind:value={addInstanceValue} type="url" placeholder="https://instance.com" aria-label="Add instance input" - on:keydown={e => { - if (e.key === "Enter") addInstance() - }} + on:keydown={e => e.key === "Enter" && addInstance()} /> <button on:click={addInstance} class="add" aria-label="Add the instance"> <AddIcon /> </button> </Row> - {#each _options[serviceOptions.frontend] as instance} + {#each _options[selectedFrontend] as instance} <Row> <span> <a href={instance} target="_blank" rel="noopener noreferrer">{instance}</a> @@ -144,9 +142,9 @@ class="add" aria-label="Remove Instance" on:click={() => { - const index = _options[serviceOptions.frontend].indexOf(instance) + const index = _options[selectedFrontend].indexOf(instance) if (index > -1) { - _options[serviceOptions.frontend].splice(index, 1) + _options[selectedFrontend].splice(index, 1) options.set(_options) } }} @@ -156,15 +154,15 @@ </Row> <hr /> {/each} - <Row></Row> {#if redirects !== "disabled" && blacklist !== "disabled"} - {#if redirects[serviceOptions.frontend] && redirects[serviceOptions.frontend]["clearnet"]} + {#if redirects[selectedFrontend] && redirects[selectedFrontend]["clearnet"]} {#each Object.entries(_config.networks) as [networkName, network]} - {#if redirects[serviceOptions.frontend] && redirects[serviceOptions.frontend][networkName]} + {#if redirects[selectedFrontend] && redirects[selectedFrontend][networkName] && redirects[selectedFrontend][networkName].length > 0} + <Row></Row> <Row><Label>{network.name}</Label></Row> <hr /> - {#each redirects[serviceOptions.frontend][networkName] as instance} + {#each redirects[selectedFrontend][networkName] as instance} <Row> <span> <a href={instance} target="_blank" rel="noopener noreferrer">{instance}</a> @@ -178,7 +176,7 @@ cloudflare </a> {/if} - {#if _options[serviceOptions.frontend].includes(instance)} + {#if _options[selectedFrontend].includes(instance)} <span style="color:grey">chosen</span> {/if} {#if pingCache && pingCache[instance]} @@ -189,9 +187,9 @@ class="add" aria-label="Add instance" on:click={() => { - if (_options[serviceOptions.frontend]) { - if (!_options[serviceOptions.frontend].includes(instance)) { - _options[serviceOptions.frontend].push(instance) + if (_options[selectedFrontend]) { + if (!_options[selectedFrontend].includes(instance)) { + _options[selectedFrontend].push(instance) options.set(_options) } } @@ -226,9 +224,19 @@ a { color: var(--text); text-decoration: none; + word-wrap: anywhere; } a:hover { text-decoration: underline; } + + :global(.margin) { + margin-right: 10px; + margin-left: 0; + } + :global(.margin_rtl) { + margin-right: 0; + margin-left: 10px; + } </style> diff --git a/src/pages/options_src/Services/RedirectType.svelte b/src/pages/options_src/Services/RedirectType.svelte new file mode 100644 index 00000000..29c169bc --- /dev/null +++ b/src/pages/options_src/Services/RedirectType.svelte @@ -0,0 +1,102 @@ +<script> + const browser = window.browser || window.chrome + + import { onDestroy } from "svelte" + import SvelteSelect from "svelte-select" + import { options, config } from "../stores" + import Row from "../../components/Row.svelte" + import Label from "../../components/Label.svelte" + import FrontendIcon from "./FrontendIcon.svelte" + import Select from "../../components/Select.svelte" + + let _options + let _config + + const unsubscribeOptions = options.subscribe(val => (_options = val)) + const unsubscribeConfig = config.subscribe(val => (_config = val)) + onDestroy(() => { + unsubscribeOptions() + unsubscribeConfig() + }) + + export let selectedService + + $: serviceConf = _config.services[selectedService] + $: serviceOptions = _options[selectedService] + $: frontendName = _options[selectedService].frontend + + let values + $: if (serviceConf.frontends[frontendName].embeddable) { + values = [ + { value: "both", name: browser.i18n.getMessage("both") || "Both" }, + { value: "sub_frame", name: browser.i18n.getMessage("onlyEmbedded") || "Only Embedded" }, + { value: "main_frame", name: browser.i18n.getMessage("onlyNotEmbedded") || "Only Not Embedded" }, + ] + } else if ( + serviceConf.frontends[frontendName].desktopApp && + Object.values(serviceConf.frontends).some(frontend => frontend.embeddable) + ) { + values = [ + { value: "both", name: "both" }, + { value: "main_frame", name: "Only Not Embedded" }, + ] + if (serviceOptions.redirectType == "sub_frame") { + serviceOptions.redirectType = "main_frame" + options.set(_options) + } + } else { + values = [{ value: "main_frame", name: "Only Not Embedded" }] + serviceOptions.redirectType = "main_frame" + options.set(_options) + } + + let embeddableFrontends = [] + $: if (serviceConf) { + embeddableFrontends = [] + for (const [frontendId, frontendConf] of Object.entries(serviceConf.frontends)) { + if (frontendConf.embeddable && frontendConf.instanceList) { + embeddableFrontends.push({ + value: frontendId, + label: frontendConf.name, + }) + } + } + } +</script> + +<Row> + <Label>{browser.i18n.getMessage("redirectType") || "Redirect Type"}</Label> + <Select + value={serviceOptions.redirectType} + onChange={e => { + serviceOptions.redirectType = e.target.options[e.target.options.selectedIndex].value + options.set(_options) + }} + {values} + /> +</Row> + +{#if serviceConf.frontends[frontendName].desktopApp && serviceOptions.redirectType != "main_frame"} + <Row> + <Label>{browser.i18n.getMessage("embedFrontend") || "Embed Frontend"}</Label> + <SvelteSelect + clearable={false} + class="svelte_select" + value={serviceOptions.embedFrontend} + on:change={e => { + serviceOptions.embedFrontend = e.detail.value + options.set(_options) + }} + items={embeddableFrontends} + > + <div class="slot" slot="item" let:item> + <FrontendIcon details={item} {selectedService} /> + {item.label} + </div> + <div class="slot" slot="selection" let:selection> + <FrontendIcon details={selection} {selectedService} /> + {selection.label} + </div> + </SvelteSelect> + </Row> +{/if} diff --git a/src/pages/options_src/Services/ServiceIcon.svelte b/src/pages/options_src/Services/ServiceIcon.svelte new file mode 100644 index 00000000..89393cf6 --- /dev/null +++ b/src/pages/options_src/Services/ServiceIcon.svelte @@ -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} diff --git a/src/pages/options_src/Services/Services.svelte b/src/pages/options_src/Services/Services.svelte new file mode 100644 index 00000000..4e719447 --- /dev/null +++ b/src/pages/options_src/Services/Services.svelte @@ -0,0 +1,202 @@ +<script> + const browser = window.browser || window.chrome + + 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" + import Instances from "./Instances.svelte" + import SvelteSelect from "svelte-select" + import ServiceIcon from "./ServiceIcon.svelte" + import FrontendIcon from "./FrontendIcon.svelte" + 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 selectedService = "youtube" + $: serviceConf = _config.services[selectedService] + $: serviceOptions = _options[selectedService] + $: frontendWebsite = serviceConf.frontends[serviceOptions.frontend].url +</script> + +<div> + <Row> + <Label> + Service: + <a href={serviceConf.url} target="_blank" rel="noopener noreferrer">{serviceConf.url}</a> + </Label> + <div dir="ltr"> + <SvelteSelect + clearable={false} + class="svelte_select" + value={selectedService} + on:change={e => (selectedService = e.detail.value)} + items={[ + ...Object.entries(_config.services).map(([serviceKey, service]) => { + return { value: serviceKey, label: service.name } + }), + ]} + > + <div class="slot" slot="item" let:item> + <ServiceIcon details={item} /> + {item.label} + </div> + <div class="slot" slot="selection" let:selection> + <ServiceIcon details={selection} /> + {selection.label} + </div> + </SvelteSelect> + </div> + </Row> + + <hr /> + + <Row> + <Label>{browser.i18n.getMessage("enable") || "Enable"}</Label> + <Checkbox + checked={serviceOptions.enabled} + onChange={e => { + serviceOptions.enabled = e.target.checked + options.set(_options) + }} + /> + </Row> + + <div style={!serviceOptions.enabled && "pointer-events: none;opacity: 0.4;user-select: none;"}> + <Row> + <Label>{browser.i18n.getMessage("showInPopup") || "Show in popup"}</Label> + <Checkbox + checked={_options.popupServices.includes(selectedService)} + onChange={e => { + if (e.target.checked && !_options.popupServices.includes(selectedService)) { + _options.popupServices.push(selectedService) + } else if (_options.popupServices.includes(selectedService)) { + const index = _options.popupServices.indexOf(selectedService) + if (index !== -1) _options.popupServices.splice(index, 1) + } + options.set(_options) + }} + /> + </Row> + + <Row> + <Label> + {browser.i18n.getMessage("frontend") || "Frontend"}: + <a href={frontendWebsite} target="_blank" rel="noopener noreferrer"> + {frontendWebsite} + </a> + </Label> + <div dir="ltr"> + <SvelteSelect + clearable={false} + dir="ltr" + class="svelte_select" + value={serviceOptions.frontend} + on:change={e => { + serviceOptions.frontend = e.detail.value + options.set(_options) + }} + items={[ + ...Object.entries(serviceConf.frontends).map(([frontendId, frontend]) => ({ + value: frontendId, + label: frontend.name, + })), + ]} + > + <div class="slot" slot="item" let:item> + <FrontendIcon details={item} {selectedService} /> + {item.label} + </div> + <div class="slot" slot="selection" let:selection> + <FrontendIcon details={selection} {selectedService} /> + {selection.label} + </div> + </SvelteSelect> + </div> + </Row> + + <RedirectType {selectedService} /> + + <Row> + <Label>{browser.i18n.getMessage("unsupportedIframesHandling") || "Unsupported embeds handling"}</Label> + <Select + value={serviceOptions.unsupportedUrls} + onChange={e => { + serviceOptions.unsupportedUrls = e.target.options[e.target.options.selectedIndex].value + options.set(_options) + }} + values={[ + { value: "bypass", name: browser.i18n.getMessage("bypass") || "Bypass" }, + { value: "block", name: browser.i18n.getMessage("block") || "Block" }, + ]} + /> + </Row> + + {#if selectedService == "search"} + <Row> + <Label> + {@html browser.i18n.getMessage("searchHint") || + `Set LibRedirect as Default Search Engine. For how to do in chromium browsers, click + <a + href="https://libredirect.github.io/docs.html#search_engine_chromium" + target="_blank" + rel="noopener noreferrer" + >here + </a>.`} + </Label> + </Row> + {/if} + + <Instances + {selectedService} + selectedFrontend={!serviceConf.frontends[serviceOptions.frontend].desktopApp || + serviceOptions.redirectType == "main_frame" + ? serviceOptions.frontend + : serviceOptions.embedFrontend} + /> + + <Row></Row> + </div> +</div> + +<style> + :global(.svelte_select) { + font-weight: bold; + --item-padding: 0 10px; + --border: none; + --border-hover: none; + --border-focused: none; + --width: 210px; + --background: var(--bg-secondary); + --list-background: var(--bg-secondary); + --item-active-background: red; + --item-is-active-bg: grey; + --item-hover-bg: grey; + --item-is-active-color: var(--text); + --padding: 0 0 0 10px; + --item-color: var(--text); + } + :global(.svelte_select .slot) { + display: flex; + justify-content: start; + align-items: center; + } + + :global(.svelte_select img, .svelte_select svg) { + margin-right: 10px; + margin-left: 0; + height: 26px; + width: 26px; + color: var(--text); + } +</style> diff --git a/src/pages/options_src/Sidebar.svelte b/src/pages/options_src/Sidebar.svelte new file mode 100644 index 00000000..97780b15 --- /dev/null +++ b/src/pages/options_src/Sidebar.svelte @@ -0,0 +1,68 @@ +<script> + const browser = window.browser || window.chrome + + import { page } from "./stores" + import GeneralIcon from "../icons/GeneralIcon.svelte" + import ServicesIcon from "../icons/ServicesIcon.svelte" + import AboutIcon from "../icons/AboutIcon.svelte" +</script> + +<div> + <a href="#general" on:click={() => page.set("general")} style={$page == "general" && "color: var(--active);"}> + <GeneralIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("general") || "General"} + </a> + <a href="#services" on:click={() => page.set("services")} style={$page == "services" && "color: var(--active);"}> + <ServicesIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("general") || "Services"} + </a> + <a href="https://libredirect.github.io" target="_blank" rel="noopener noreferrer"> + <AboutIcon class="margin margin_{document.body.dir}" /> + {browser.i18n.getMessage("about") || "About"} + </a> +</div> + +<style> + div { + display: flex; + flex-direction: column; + margin: 0 20px; + } + + a { + display: flex; + align-items: center; + font-size: 18px; + text-decoration: none; + color: var(--text); + transition: 0.1s; + margin: 10px; + } + + a:hover { + color: var(--active); + } + + @media (max-width: 1250px) { + div { + flex-direction: row; + justify-content: center; + margin: 0; + } + } + + @media (max-width: 715px) { + a { + margin: 5px; + } + } + + :global(.margin) { + margin-right: 5px; + margin-left: 0; + } + :global(.margin_rtl) { + margin-right: 0; + margin-left: 5px; + } +</style> diff --git a/src/pages/src/main.js b/src/pages/options_src/main.js index c4012f4a..c4012f4a 100644 --- a/src/pages/src/main.js +++ b/src/pages/options_src/main.js diff --git a/src/pages/src/stores.js b/src/pages/options_src/stores.js index 782f6064..782f6064 100644 --- a/src/pages/src/stores.js +++ b/src/pages/options_src/stores.js diff --git a/src/pages/popup/index.html b/src/pages/popup/index.html new file mode 100644 index 00000000..b197d4a7 --- /dev/null +++ b/src/pages/popup/index.html @@ -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='../fonts/styles.css'> + <script defer src='build/bundle.js'></script> +</head> + +<body> +</body> + +</html> \ No newline at end of file diff --git a/src/pages/popup/popup.js b/src/pages/popup/popup.js deleted file mode 100644 index 77a43000..00000000 --- a/src/pages/popup/popup.js +++ /dev/null @@ -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 = "" - } - } -}) diff --git a/src/pages/popup/popup.pug b/src/pages/popup/popup.pug deleted file mode 100644 index ed4c7319..00000000 --- a/src/pages/popup/popup.pug +++ /dev/null @@ -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") diff --git a/src/pages/popup/style.css b/src/pages/popup/style.css deleted file mode 100644 index 41510615..00000000 --- a/src/pages/popup/style.css +++ /dev/null @@ -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; -} diff --git a/src/pages/popup/switches.pug b/src/pages/popup/switches.pug deleted file mode 100644 index 20ed8c61..00000000 --- a/src/pages/popup/switches.pug +++ /dev/null @@ -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") \ No newline at end of file diff --git a/src/pages/src/App.svelte b/src/pages/popup_src/App.svelte index 8cceb5d1..df37d55d 100644 --- a/src/pages/src/App.svelte +++ b/src/pages/popup_src/App.svelte @@ -1,14 +1,13 @@ <script> - let browser = window.browser || window.chrome + const browser = window.browser || window.chrome - import General from "./General/General.svelte" import utils from "../../assets/javascripts/utils.js" import { onDestroy } from "svelte" import servicesHelper from "../../assets/javascripts/services.js" import { onMount } from "svelte" - import Sidebar from "./Sidebar.svelte" + import Buttons from "./Buttons.svelte" + import { options, config, page } from "./stores" - import Services from "./Services/Services.svelte" let _options const unsubscribeOptions = options.subscribe(val => { @@ -29,7 +28,6 @@ onMount(async () => { let opts = await utils.getOptions() if (!opts) { - console.log("init defulats") await servicesHelper.initDefaults() opts = await utils.getOptions() } @@ -82,37 +80,35 @@ --danger: {cssVariables.danger}; --light-grey: {cssVariables.lightGrey};" > - <Sidebar /> - {#if _page == "general"} - <General /> - {:else if _page == "services"} - <Services /> - {/if} + <Buttons /> </div> {:else} <p>Loading...</p> {/if} <style> - :global(body) { - width: 100vw; - height: 100vh; + :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%; - display: grid; - grid-template-columns: min-content 700px; margin: 0; - padding-top: 50px; - justify-content: center; + padding: 10px; + padding-top: 20px; font-family: "Inter"; - box-sizing: border-box; font-size: 16px; background-color: var(--bg-main); color: var(--text); - overflow: scroll; } </style> diff --git a/src/pages/popup_src/Buttons.svelte b/src/pages/popup_src/Buttons.svelte new file mode 100644 index 00000000..bfa162f8 --- /dev/null +++ b/src/pages/popup_src/Buttons.svelte @@ -0,0 +1,118 @@ +<script> + const 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 { onDestroy } from "svelte" + import servicesHelper from "../../assets/javascripts/services" + import Switch from "./components/Switch.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)) + servicesHelper.computeService(url).then(r => (currentService = r)) + } + }) +</script> + +<div class={document.body.dir}> + {#if redirect} + <Row class="interactive" on:click={() => browser.runtime.sendMessage("redirectTab")}> + <Label>{browser.i18n.getMessage("redirect") || "Redirect"}</Label> + <RedirectIcon /> + </Row> + {/if} + + {#if switchInstance} + <Row + class="interactive" + on:click={async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url) })} + > + <Label>{browser.i18n.getMessage("switchInstance") || "Switch Instance"}</Label> + <SwitchInstanceIcon /> + </Row> + {/if} + + {#if redirectToOriginal} + <Row class="interactive" on:click={() => servicesHelper.copyRaw(url)}> + <Label>{browser.i18n.getMessage("copyOriginal") || "Copy Original"}</Label> + <CopyIcon /> + </Row> + <Row class="interactive" on:click={() => browser.runtime.sendMessage("reverseTab")}> + <Label>{browser.i18n.getMessage("redirectToOriginal" || "Redirect to Original")}</Label> + <RedirectToOriginalIcon /> + </Row> + {/if} + + {#if redirect || switchInstance || redirectToOriginal} + <hr /> + {/if} + + {#if currentService} + <Switch serviceKey={currentService} {url} /> + <hr /> + {/if} + + {#each _options.popupServices as serviceKey} + {#if currentService !== serviceKey} + <Switch {serviceKey} {url} /> + {/if} + {/each} + + <hr /> + + <Row class="interactive" on:click={() => window.open(browser.runtime.getURL("pages/options/index.html"), "_blank")}> + <Label>{browser.i18n.getMessage("settings")}</Label> + <SettingsIcon /> + </Row> +</div> + +<style> + :global(.interactive) { + transition: 0.1s; + } + :global(.interactive:hover) { + color: var(--active); + cursor: pointer; + } + :global(.interactive:active) { + transform: translateY(1px); + } + + :global(img, svg) { + margin-right: 10px; + margin-left: 0; + height: 26px; + width: 26px; + color: var(--text); + } + + :global(.rtl img, .rtl svg) { + margin-right: 0; + margin-left: 10px; + } +</style> diff --git a/src/pages/popup_src/components/Row.svelte b/src/pages/popup_src/components/Row.svelte new file mode 100644 index 00000000..a4d78f07 --- /dev/null +++ b/src/pages/popup_src/components/Row.svelte @@ -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> + \ No newline at end of file diff --git a/src/pages/popup_src/components/ServiceIcon.svelte b/src/pages/popup_src/components/ServiceIcon.svelte new file mode 100644 index 00000000..89393cf6 --- /dev/null +++ b/src/pages/popup_src/components/ServiceIcon.svelte @@ -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} diff --git a/src/pages/popup_src/components/Switch.svelte b/src/pages/popup_src/components/Switch.svelte new file mode 100644 index 00000000..e581e5f4 --- /dev/null +++ b/src/pages/popup_src/components/Switch.svelte @@ -0,0 +1,67 @@ +<script> + const browser = window.browser || window.chrome + + import Checkbox from "../../components/Checkbox.svelte" + import Label from "../../components/Label.svelte" + import SwitchInstanceIcon from "../../icons/SwitchInstanceIcon.svelte" + import Row from "./Row.svelte" + import ServiceIcon from "./ServiceIcon.svelte" + import { onDestroy } from "svelte" + import servicesHelper from "../../../assets/javascripts/services" + import { options, config } from "../stores" + + let _options + let _config + + const unsubscribeOptions = options.subscribe(val => (_options = val)) + const unsubscribeConfig = config.subscribe(val => (_config = val)) + onDestroy(() => { + unsubscribeOptions() + unsubscribeConfig() + }) + + export let serviceKey + export let url +</script> + +<Row> + <div + class="interactive" + 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> + <Checkbox + class="margin margin_{document.body.dir}" + label="Enable" + checked={_options[serviceKey].enabled} + onChange={e => { + _options[serviceKey].enabled = e.target.checked + options.set(_options) + }} + /> + <SwitchInstanceIcon + class="interactive" + on:click={async () => browser.tabs.update({ url: await servicesHelper.switchInstance(url, serviceKey) })} + /> + </div> +</Row> + +<style> + div { + display: flex; + align-items: center; + } + + :global(.margin) { + margin-right: 5px; + margin-left: 0; + } + :global(.margin_rtl) { + margin-right: 0; + margin-left: 5px; + } +</style> diff --git a/src/pages/popup_src/main.js b/src/pages/popup_src/main.js new file mode 100644 index 00000000..c4012f4a --- /dev/null +++ b/src/pages/popup_src/main.js @@ -0,0 +1,7 @@ +import App from "./App.svelte" + +const app = new App({ + target: document.body, +}) + +export default app diff --git a/src/pages/popup_src/stores.js b/src/pages/popup_src/stores.js new file mode 100644 index 00000000..782f6064 --- /dev/null +++ b/src/pages/popup_src/stores.js @@ -0,0 +1,5 @@ +import { writable } from "svelte/store" + +export const options = writable(null) +export const config = writable(null) +export const page = writable("general") diff --git a/src/pages/src/General/General.svelte b/src/pages/src/General/General.svelte deleted file mode 100644 index 1a5e8329..00000000 --- a/src/pages/src/General/General.svelte +++ /dev/null @@ -1,70 +0,0 @@ -<script> - let browser = window.browser || window.chrome - - import Exceptions from "./Exceptions.svelte" - import SettingsButtons from "./SettingsButtons.svelte" - import RowSelect from "../components/RowSelect.svelte" - import Checkbox from "../components/RowCheckbox.svelte" - import { options } from "../stores" - import { onDestroy } from "svelte" - - let _options - const unsubscribe = options.subscribe(val => (_options = val)) - onDestroy(unsubscribe) - - let bookmarksPermission - browser.permissions.contains({ permissions: ["bookmarks"] }, r => (bookmarksPermission = r)) - $: if (bookmarksPermission) { - browser.permissions.request({ permissions: ["bookmarks"] }, r => (bookmarksPermission = r)) - } else { - browser.permissions.remove({ permissions: ["bookmarks"] }) - bookmarksPermission = false - } -</script> - -<div> - <RowSelect - label="Theme" - values={[ - { value: "detect", name: "Auto" }, - { value: "light", name: "Light" }, - { value: "dark", name: "Dark" }, - ]} - value={_options.theme} - onChange={e => { - _options["theme"] = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - ariaLabel="select theme" - /> - - <RowSelect - label="Fetch public instances" - value={_options.fetchInstances} - onChange={e => { - _options["fetchInstances"] = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - ariaLabel="Select fetch public instances" - values={[ - { value: "github", name: "GitHub" }, - { value: "codeberg", name: "Codeberg" }, - { value: "disable", name: "Disable" }, - ]} - /> - - <Checkbox - label="Redirect Only in Incognito" - checked={_options.redirectOnlyInIncognito} - onChange={e => { - _options["redirectOnlyInIncognito"] = e.target.checked - options.set(_options) - }} - /> - - <Checkbox label="Bookmarks menu" bind:checked={bookmarksPermission} /> - - <Exceptions opts={_options} /> - - <SettingsButtons opts={_options} /> -</div> diff --git a/src/pages/src/Services/RedirectType.svelte b/src/pages/src/Services/RedirectType.svelte deleted file mode 100644 index 92b8c6d1..00000000 --- a/src/pages/src/Services/RedirectType.svelte +++ /dev/null @@ -1,84 +0,0 @@ -<script> - import { onDestroy } from "svelte" - - import RowSelect from "../components/RowSelect.svelte" - import { options, config } from "../stores" - - let _options - let _config - - const unsubscribeOptions = options.subscribe(val => (_options = val)) - const unsubscribeConfig = config.subscribe(val => (_config = val)) - onDestroy(() => { - unsubscribeOptions() - unsubscribeConfig() - }) - - export let selectedService - - $: serviceConf = _config.services[selectedService] - $: serviceOptions = _options[selectedService] - $: frontendName = _options[selectedService].frontend - - let values - $: if (serviceConf.frontends[frontendName].embeddable) { - values = [ - { value: "both", name: "Both" }, - { value: "sub_frame", name: "Only Embedded" }, - { value: "main_frame", name: "Only Not Embedded" }, - ] - } else if ( - serviceConf.frontends[frontendName].desktopApp && - Object.values(serviceConf.frontends).some(frontend => frontend.embeddable) - ) { - values = [ - { value: "both", name: "both" }, - { value: "main_frame", name: "Only Not Embedded" }, - ] - if (serviceOptions.redirectType == "sub_frame") { - serviceOptions.redirectType = "main_frame" - options.set(_options) - } - } else { - values = [{ value: "main_frame", name: "Only Not Embedded" }] - serviceOptions.redirectType = "main_frame" - options.set(_options) - } - - let embeddableFrontends = [] - $: (() => { - if (serviceConf) { - embeddableFrontends = [] - for (const [frontendId, frontendConf] of Object.entries(serviceConf.frontends)) { - if (frontendConf.embeddable && frontendConf.instanceList) { - embeddableFrontends.push({ - value: frontendId, - name: frontendConf.name, - }) - } - } - } - })() -</script> - -<RowSelect - label="Redirect Type" - value={serviceOptions.redirectType} - onChange={e => { - serviceOptions.redirectType = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - {values} -/> - -{#if serviceConf.frontends[frontendName].desktopApp && serviceOptions.redirectType != "main_frame"} - <RowSelect - label="Embed Frontend" - value={_options.embedFrontend} - onChange={e => { - serviceOptions.embedFrontend = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - values={embeddableFrontends} - /> -{/if} diff --git a/src/pages/src/Services/Services.svelte b/src/pages/src/Services/Services.svelte deleted file mode 100644 index b5d9285c..00000000 --- a/src/pages/src/Services/Services.svelte +++ /dev/null @@ -1,119 +0,0 @@ -<script> - let browser = window.browser || window.chrome - - 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, onMount } from "svelte" - import Instances from "./Instances.svelte" - - let _options - let _config - - const unsubscribeOptions = options.subscribe(val => (_options = val)) - const unsubscribeConfig = config.subscribe(val => (_config = val)) - onDestroy(() => { - unsubscribeOptions() - unsubscribeConfig() - }) - - let selectedService = "youtube" - - $: serviceConf = _config.services[selectedService] - $: serviceOptions = _options[selectedService] -</script> - -<div> - <Row> - <Label> - Service: - <a href={serviceConf.url} target="_blank" rel="noopener noreferrer">{serviceConf.url}</a> - </Label> - <Select - value={selectedService} - values={[ - ...Object.entries(_config.services).map(([serviceId, service]) => { - return { value: serviceId, name: service.name } - }), - ]} - onChange={e => (selectedService = e.target.options[e.target.options.selectedIndex].value)} - /> - </Row> - - <hr /> - - <Checkbox - label="Enable" - checked={serviceOptions.enabled} - onChange={e => { - serviceOptions.enabled = e.target.checked - options.set(_options) - }} - /> - - <div style={!serviceOptions.enabled && "pointer-events: none;opacity: 0.4;user-select: none;"}> - <Checkbox - label="Show in popup" - checked={_options.popupServices.includes(selectedService)} - onChange={e => { - if (e.target.checked && !_options.popupServices.includes(selectedService)) { - _options.popupServices.push(selectedService) - } else if (_options.popupServices.includes(selectedService)) { - const index = _options.popupServices.indexOf(selectedService) - if (index !== -1) _options.popupServices.splice(index, 1) - } - options.set(_options) - }} - /> - - <Row> - <Label> - Frontend: - <a href={serviceConf.frontends[serviceOptions.frontend].url} target="_blank" rel="noopener noreferrer" - >{serviceConf.frontends[serviceOptions.frontend].url}</a - > - </Label> - <Select - value={serviceOptions.frontend} - values={[ - ...Object.entries(serviceConf.frontends).map(([frontendId, frontend]) => ({ - value: frontendId, - name: frontend.name, - })), - ]} - onChange={e => { - serviceOptions.frontend = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - /> - </Row> - - <RedirectType {selectedService} /> - - <RowSelect - label="Unsupported iframes handling" - value={serviceOptions.unsupportedUrls} - onChange={e => { - serviceOptions.unsupportedUrls = e.target.options[e.target.options.selectedIndex].value - options.set(_options) - }} - values={[ - { value: "bypass", name: "Bypass" }, - { value: "block", name: "Block" }, - ]} - /> - - {#if selectedService == "search"} - <div> - Set LibRedirect as Default Search Engine. For how to do in chromium browsers, click - <a href="https://libredirect.github.io/docs.html#search_engine_chromium">here</a>. - </div> - {/if} - - <Instances {selectedService} /> - </div> -</div> diff --git a/src/pages/src/Sidebar.svelte b/src/pages/src/Sidebar.svelte deleted file mode 100644 index be59a731..00000000 --- a/src/pages/src/Sidebar.svelte +++ /dev/null @@ -1,43 +0,0 @@ -<script> - import { page } from "./stores" - import GeneralIcon from "./icons/GeneralIcon.svelte" - import ServicesIcon from "./icons/ServicesIcon.svelte" - import AboutIcon from "./icons/AboutIcon.svelte" -</script> - -<div> - <a href="#general" on:click={() => page.set("general")} style={$page == "general" && "color: var(--active);"}> - <GeneralIcon style="margin-right: 5px" /> - <span data-localise="__MSG_general__">General</span> - </a> - <a href="#services" on:click={() => page.set("services")} style={$page == "services" && "color: var(--active);"}> - <ServicesIcon style="margin-right: 5px" /> - <span data-localise="__MSG_general__">Services</span> - </a> - <a href="https://libredirect.github.io" target="_blank" rel="noopener noreferrer"> - <AboutIcon style="margin-right: 5px" /> - <span data-localise="__MSG_about__">About</span> - </a> -</div> - -<style> - div { - display: flex; - flex-direction: column; - margin: 0 20px; - } - - a { - display: flex; - align-items: center; - font-size: 18px; - text-decoration: none; - color: var(--text); - transition: 0.1s; - margin: 10px; - } - - a:hover { - color: var(--active); - } -</style> diff --git a/src/pages/src/components/RowCheckbox.svelte b/src/pages/src/components/RowCheckbox.svelte deleted file mode 100644 index b7ccab93..00000000 --- a/src/pages/src/components/RowCheckbox.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<script> - import Row from "./Row.svelte" - import Checkbox from "./Checkbox.svelte" - import Label from "./Label.svelte" - - export let label - export let checked - export let onChange -</script> - -<Row> - <Label>{label}</Label> - <Checkbox bind:checked {onChange} /> -</Row> diff --git a/src/pages/src/components/RowSelect.svelte b/src/pages/src/components/RowSelect.svelte deleted file mode 100644 index d685803e..00000000 --- a/src/pages/src/components/RowSelect.svelte +++ /dev/null @@ -1,19 +0,0 @@ -<script> - import Row from "./Row.svelte" - import Select from "./Select.svelte" - import Label from "./Label.svelte" - - export let label - export let values - export let value - export let onChange - export let ariaLabel -</script> - -<Row> - <Label>{label}</Label> - <Select {value} {values} {onChange} {ariaLabel} /> -</Row> - -<style> -</style> diff --git a/src/pages/src/icons/ImportIcon.svelte b/src/pages/src/icons/ImportIcon.svelte deleted file mode 100644 index f022b4f0..00000000 --- a/src/pages/src/icons/ImportIcon.svelte +++ /dev/null @@ -1,5 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"> - <path - d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" - /> - </svg> \ No newline at end of file diff --git a/src/pages/stylesheets/styles.css b/src/pages/stylesheets/styles.css deleted file mode 100644 index ca6f0dca..00000000 --- a/src/pages/stylesheets/styles.css +++ /dev/null @@ -1,449 +0,0 @@ -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"); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: "Vazirmatn"; - src: url("Vazirmatn-VariableFont_wght.ttf"); - font-weight: normal; - 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 { - flex-direction: column; - width: 95vw; - align-items: center; - padding: 40px 0px; - } - - section.links { - flex-direction: row; - width: 95vw; - padding: 0 55px; - } - - section.block-option { - width: 95vw; - } - - div.checklist div x { - overflow: hidden; - } -} - -html.mobile img, -html.mobile svg { - margin-right: 10px; - height: 30px; - width: 30px; - color: var(--text); -} - -html.mobile div.block { - padding: 0 15px; - justify-content: space-between; - display: flex; - align-items: center; - margin-top: 20px; - margin-bottom: 20px; -} - -html.mobile div.block input[type="checkbox"] { - width: 58px; - height: 30px; -} - -html.mobile div.block input[type="checkbox"]::before { - width: 24px; - height: 24px; - top: 3px; - left: 3.5px; -} - -html.mobile div.block input[type="checkbox"]:checked::before { - left: 30px; -} - -html.mobile body.option { - flex-direction: column; - width: 100%; - padding: 0; - align-items: center; -} - -html.mobile section.links { - flex-direction: row; - width: 100%; - padding: 0 55px; -} - -html.mobile section.block-option { - width: 100%; -} |