- Userscript
- {#if scriptChecking}
- {showInstallPrompt}
- {:else}
- {scriptInstalled ? "Installed" : "Detected"}:
- {showInstallPrompt}
- {/if}
-
-{/if}
-{#if errorNotification}
- Be sure you trust the author before saving remote code to your device.
-
- {@html iconLoader}
- {#if abort}
-
- Fetching resources, cancel request
-
- {/if}
+
+
+ {@html iconLoader}
+ {#if abort}
+
+ Fetching resources,
+
+ {/if}
diff --git a/src/shared/Components/LogoIcon.svelte b/src/shared/Components/LogoIcon.svelte
new file mode 100644
index 00000000..7b5f74df
--- /dev/null
+++ b/src/shared/Components/LogoIcon.svelte
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/src/shared/Components/LogoText.svelte b/src/shared/Components/LogoText.svelte
new file mode 100644
index 00000000..e5ad9068
--- /dev/null
+++ b/src/shared/Components/LogoText.svelte
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/src/shared/Components/Tag.svelte b/src/shared/Components/Tag.svelte
index 13e80cf2..80e00954 100644
--- a/src/shared/Components/Tag.svelte
+++ b/src/shared/Components/Tag.svelte
@@ -1,55 +1,55 @@
diff --git a/src/shared/Components/Toggle.svelte b/src/shared/Components/Toggle.svelte
index cc26375d..9b1d338f 100644
--- a/src/shared/Components/Toggle.svelte
+++ b/src/shared/Components/Toggle.svelte
@@ -1,70 +1,68 @@
-
-
+
+
diff --git a/src/shared/colors.js b/src/shared/colors.js
new file mode 100644
index 00000000..73d9001f
--- /dev/null
+++ b/src/shared/colors.js
@@ -0,0 +1,10 @@
+/**
+ * Theme colors for console log css
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output}
+ */
+export const colors = {
+ inherit: "color: inherit;",
+ blue: "color: light-dark( #317eff, #006fff);",
+ green: "color: light-dark( #2bb239, #60f36c);",
+ yellow: "color: light-dark( #b8722c, #fff600);",
+};
diff --git a/src/shared/dev.js b/src/shared/dev.js
deleted file mode 100644
index 9b1037d2..00000000
--- a/src/shared/dev.js
+++ /dev/null
@@ -1,502 +0,0 @@
-import {parse, uniqueId, wait} from "./utils";
-
-/**
- *
- * @param {("css"|"js")} type
- * @param {boolean?} updates
- * @param {boolean?} longName
- * @returns
- */
-function generateFile(type, updates = false, longName = false, request = false) {
- let canUpdate = updates;
- const uid = uniqueId();
- let name = request ? `${uid}-request-${type}` : `${uid}-example-${type}`;
- if (longName) name = `${uid}${uid}${uid}-example-${type}`;
- const randomDate = +(new Date() - Math.floor(Math.random() * 10000000000));
- let content = "// ==UserScript=="
- + `\n// @name ${name}`
- + `\n// @description Custom description for userscript with name "${name}"`
- + "\n// @match *://*.*"
- + "\n// @exclude-match https://github.com/quoid/userscripts"
- + "\n// @version 1.0"
- + "\n// @noframes"
- + "\n// ==/UserScript=="
- + `\n\nconsole.log("I am ${name}");`;
- if (type === "css") {
- content = content.replace("// ==UserScript==", "/* ==UserStyle==");
- content = content.replace("// ==/UserScript==", "==/UserStyle== */");
- content = content.replaceAll("// @", "@");
- content = content.replace(
- `console.log("I am ${name}");`,
- "#id,\n.class\n.pseudo-element::after {\n color: red\n}"
- );
- canUpdate = false;
- }
- if (request) {
- content = content.replace("// @noframes", "// @noframes\n// @run-at request");
- }
- if (canUpdate) {
- content = content.replace(
- "1.0",
- "1.0\n// @updateURL https://www.k21p.com/example.user.js"
- );
- content = content.replace(
- `console.log("I am ${name}");`,
- `console.log("I am ${name} and you can update me!");`
- );
- }
- return {
- content,
- filename: `${name}.${type}`,
- lastModified: randomDate,
- name,
- request,
- type
- };
-}
-
-const files = [
- generateFile("js", true, true),
- generateFile("css"),
- generateFile("js", false, false, true),
- ...Array.from({length: 7}, () => generateFile("js"))
-];
-
-const _browser = {
- delay: 200,
- platform: "macos", // ios || macos
- runtime: {
- getURL() {
- return "https://www.example.com/";
- },
- async sendMessage(message, responseCallback) {
- const name = message.name;
- console.info(`Got message: ${name}`);
- let response = {};
- if (name === "REFRESH_SESSION_RULES") {
- response = {success: true};
- }
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- },
- async sendNativeMessage(message, responseCallback) {
- const name = message.name;
- console.info(`Got message: ${name}`);
- let response = {};
- if (name === "PAGE_INIT_DATA") {
- response = {
- saveLocation: "/Users/someone/Library/Directory",
- version: "5.0.0",
- build: "55"
- };
- } else if (name === "PAGE_LEGACY_IMPORT") {
- response = {
- active: "true",
- autoCloseBrackets: "true",
- autoHint: "true",
- blacklist: [],
- descriptions: "true",
- languageCode: "en",
- lint: "true",
- log: "false",
- showCount: "true",
- showInvisibles: "true",
- sortOrder: "lastModifiedDesc",
- tabSize: "4"
- };
- } else if (name === "PAGE_ALL_FILES") {
- response = [];
- files.forEach(file => {
- const content = file.content;
- const parsed = parse(content);
- const metadata = parsed.metadata;
- const canUpdate = !!(metadata.version && metadata.updateURL);
- const scriptData = {
- canUpdate,
- content,
- description: metadata.description ? metadata.description[0] : "",
- disabled: false,
- filename: file.filename,
- lastModified: file.lastModified,
- metadata,
- name: metadata.name[0],
- request: file.request,
- // type: file.filename.substring(file.filename.lastIndexOf(".") + 1)
- type: file.type
- };
- response.push(scriptData);
- });
- } else if (name === "TOGGLE_ITEM") {
- response = {success: true};
- // response = {error: true};
- } else if (name === "PAGE_UPDATE_SETTINGS") {
- response = {success: true};
- } else if (name === "PAGE_UPDATE_BLACKLIST") {
- response = {success: true};
- } else if (name === "PAGE_NEW_REMOTE") {
- const result = await getRemoteFileContents(message.url);
- response = result;
- } else if (name === "PAGE_SAVE") {
- const newContent = message.content;
- const oldFilename = message.item.filename;
- const parsed = parse(newContent);
- const lastModified = Date.now();
- let canUpdate = false;
- // script failed to parse
- if (!parsed) {
- return {error: "save failed, file has invalid metadata"};
- }
- const metaName = parsed.metadata.name[0];
- const newFilename = `${metaName}.${message.item.type}`;
- // filename length too long
- if (newFilename.length > 255) {
- return {error: "save failed, filename too long!"};
- }
-
- // check if file can be remotely updated
- if (parsed.metadata.version && parsed.metadata.updateURL) {
- canUpdate = true;
- }
-
- const success = {
- canUpdate,
- content: newContent,
- filename: newFilename,
- lastModified,
- name
- };
-
- // add description if in file metadata
- if (parsed.metadata.description) {
- // const foo = parsed.metadata;
- success.description = parsed.metadata.description[0];
- }
- // check if declarative network request
- if (
- parsed.metadata["run-at"]
- && parsed.metadata["run-at"][0] === "request"
- ) {
- success.request = true;
- }
- // overwriting
- if (newFilename.toLowerCase() === oldFilename.toLowerCase()) {
- saveFile(newContent, lastModified, newFilename, oldFilename);
- return success;
- }
-
- // not overwriting, check if filename for that type is taken
- if (files.find(a => a.filename.toLowerCase() === newFilename.toLowerCase())) {
- return {error: "save failed, name already taken!"};
- }
-
- // not overwriting but all validation passed
- saveFile(newContent, lastModified, newFilename, oldFilename);
- return success;
- } else if (name === "PAGE_UPDATE") {
- const url = parse(message.content).metadata.updateURL;
- await wait(500);
- const result = await getRemoteFileContents(url);
- response = result;
- // response.error = "Something went wrong!";
- // response.info = "No updates found";
- } else if (name === "TOGGLE_EXTENSION") {
- // response = {error: "Failed toggle extension"};
- response = {success: true};
- } else if (name === "POPUP_UPDATE_ALL" || name === "POPUP_UPDATE_SINGLE") {
- // response = {error: "Failed refresh scripts"};
- response = {
- items: [
- {
- name: "Google Images Restored",
- filename: "Google Images Restored.js",
- disabled: false,
- type: "js"
- },
- {
- name: "Wikipedia Mobile Redirect",
- filename: "Wikipedia Mobile Redirect.js",
- disabled: true,
- type: "js"
- },
- {
- name: "A Special Userscript",
- filename: "A Special Userscript.js",
- disabled: false,
- type: "js"
- },
- {
- name: "CSS Adblock",
- filename: "CSS Adblock.css",
- disabled: false,
- type: "css"
- },
- {
- name: "New Userscript With a Really Really Long Name",
- filename: "New Userscript With a Really Really Long Name.css",
- disabled: true,
- type: "css"
- },
- {
- name: "Subframe Script Managerial Staffing Company",
- filename: "Subframe Script.js",
- disabled: false,
- subframe: true,
- type: "css"
- }
- ],
- updates: []
- };
- } else if (name === "POPUP_CHECK_UPDATES") {
- response = {
- updates: [
- {
- filename: "Google Images Restored.js",
- name: "Google Images Restored",
- url: "https://www.k21p.com"
- },
- {
- filename: "New Userscript With a Really Really Long Name.js",
- name: "New Userscript With a Really Really Long Name",
- url: "https://www.filmgarb.com"
- }
- ]
- };
- } else if (name === "POPUP_INIT") {
- response.initData = {
- active: "true",
- items: [
- {
- name: "Google Images Restored",
- filename: "Google Images Restored.js",
- disabled: false,
- type: "js"
- },
- {
- name: "Subframe Script Managerial Staffing Company",
- filename: "Subframe Script.js",
- disabled: false,
- subframe: true,
- type: "css"
- }
- ],
- updates: [
- {
- filename: "Google Images Restored.js",
- name: "Google Images Restored",
- url: "https://www.k21p.com"
- },
- {
- filename: "New Userscript With a Really Really Long Name.js",
- name: "New Userscript With a Really Really Long Name",
- url: "https://www.filmgarb.com"
- }
- ]
- };
- } else if (name === "POPUP_MATCHES") {
- response = {
- matches: [
- ...files,
- {
- name: "Subframe Script Managerial Staffing Company",
- filename: "Subframe Script.js",
- disabled: false,
- subframe: true,
- type: "js"
- }
- ]
- };
- } else if (name === "POPUP_UPDATES") {
- response = {
- updates: [
- {
- filename: "Google Images Restored.js",
- name: "Google Images Restored",
- url: "https://www.k21p.com"
- },
- {
- filename: "New Userscript With a Really Really Long Name.js",
- name: "New Userscript With a Really Really Long Name",
- url: "https://www.filmgarb.com"
- }
- ]
- };
- response.updates = [];
- } else if (name === "REQ_PLATFORM") {
- response = {platform: _browser.platform};
- } else if (name === "POPUP_OPEN_EXTENSION_PAGE") {
- response = {error: "Failed to get page url"};
- window.open("https://github.com/quoid/userscripts");
- } else if (name === "OPEN_SAVE_LOCATION") {
- if (_browser.platform === "macos") {
- response = {success: true};
- } else {
- response = {
- items: [
- {
- name: "Google Images Restored",
- filename: "Google Images Restored.js",
- disabled: false,
- type: "js",
- metadata: []
- },
- {
- name: "Subframe Script Managerial Staffing Company",
- filename: "Subframe Script.js",
- disabled: false,
- type: "css",
- metadata: []
- },
- {
- name: "Another Script from Managerial Staffing Company",
- filename: "Cool Script.js",
- disabled: false,
- type: "js",
- metadata: []
- }
- ]
- };
- }
- } else if (name === "POPUP_INSTALL_CHECK") {
- response = random([
- {success: "Click to install", installed: false},
- {success: "Click to re-install", installed: true}
- ]);
- response.metadata = {
- description: "This userscript re-implements the \"View Image\" and \"Search by image\" buttons into google images.",
- grant: ["GM.getValue", "GM.setValue", "GM.xmlHttpRequest"],
- match: ["https://www.example.com/*", "https://www.example.com/somethingReallylong/goesRightHere"],
- name: "Test Install Userscript",
- require: ["https://code.jquery.com/jquery-3.5.1.min.js", "https://code.jquery.com/jquery-1.7.1.min.js"],
- source: "https://greasyforx.org/scripts/00000-something-something-long-name/code/Something%20something%20long20name.user.js"
- };
- // response.error = "something went wrong (dev)";
- }
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- },
- connectNative: () => ({
- onMessage: {
- addListener: () => console.info("connectNative - addListener")
- }
- })
- },
- tabs: {
- getCurrent(/* responseCallback */) {
- const response = random([
- {url: "https://www.filmgarb.com/foo.user.js", id: 101},
- {url: `${window.location.origin}/src/shared/dev/DEMO.Alert-URL.user.js`, id: 102},
- {url: `${window.location.origin}/src/shared/dev/DEMO.Alert-URL.user.js`, id: 103}, // increase probability
- {url: window.location.href, id: 10}
- ]);
- console.info("browser.tabs.getCurrent", response);
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- },
- query(message, responseCallback) {
- const response = [{url: "https://www.filmgarb.com/foo.user.js", id: 101}];
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- },
- sendMessage(tabId, message, responseCallback) {
- let response = {};
- if (message.name === "DEMO_MSG") {
- response = {};
- // response.error = "something went wrong (dev)";
- }
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- }
- },
- webNavigation: {
- getAllFrames(message, responseCallback) {
- const response = [];
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- }
- },
- storage: {
- local: {
- get(items, responseCallback) {
- const response = {};
- if (!responseCallback) {
- return new Promise(resolve => {
- setTimeout(() => resolve(response), _browser.delay);
- });
- }
- setTimeout(() => responseCallback(response), _browser.delay);
- },
- set() {
- return new Promise(resolve => {
- setTimeout(() => resolve(), _browser.delay);
- });
- },
- remove: () => new Promise(resolve => {
- setTimeout(() => resolve(), _browser.delay);
- }),
- onChanged: {
- addListener: () => undefined
- }
- }
- }
-};
-
-async function getRemoteFileContents(url) {
- const result = {};
- await fetch(url).then(response => {
- if (!response.ok) throw Error(response.statusText);
- return response.text();
- }).then(text => {
- result.content = text;
- }).catch(error => {
- console.error(error);
- result.error = "Remote url bad response!";
- });
- return result;
-}
-
-function saveFile(content, lastMod, newFilename, oldName) {
- const ind = files.findIndex(f => f.filename === oldName);
- const s = {
- content,
- filename: newFilename,
- lastModified: lastMod
- };
- if (ind !== -1) {
- // overwrite at index
- files[ind] = s;
- } else {
- // add to beginning of array
- files.unshift(s);
- }
-}
-
-function random(array) {
- return array[Math.floor(Math.random() * array.length)];
-}
-
-export const browser = _browser;
-
-export default {
- browser: _browser
-};
diff --git a/src/shared/img/icon-bug.svg b/src/shared/img/icon-bug.svg
new file mode 100644
index 00000000..400d41b4
--- /dev/null
+++ b/src/shared/img/icon-bug.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/shared/img/icon-loader.svg b/src/shared/img/icon-loader.svg
index b75290bb..64cc3f45 100644
--- a/src/shared/img/icon-loader.svg
+++ b/src/shared/img/icon-loader.svg
@@ -1,4 +1,4 @@
-