Update dependencies
This commit is contained in:
parent
c0bad165a2
commit
872ca6d576
19 changed files with 2356 additions and 5020 deletions
|
@ -6,7 +6,6 @@ module.exports = {
|
|||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"semi": true,
|
||||
"svelteSortOrder": "scripts-markup-styles"
|
||||
"semi": true
|
||||
}
|
||||
|
|
57
package.json
57
package.json
|
@ -4,42 +4,44 @@
|
|||
"description": "Lingo is a small browser extension to help you learn languages",
|
||||
"main": "webpack.config.js",
|
||||
"dependencies": {
|
||||
"@asmagin/google-translate-api": "^8.0.2",
|
||||
"@sveltejs/svelte-virtual-list": "^3.0.1",
|
||||
"svelte-feather-icons": "^3.2.2",
|
||||
"svelte-select": "^3.11.0",
|
||||
"tippy.js": "^6.2.5"
|
||||
"svelte-feather-icons": "^4.0.0",
|
||||
"svelte-select": "^4.4.7",
|
||||
"tippy.js": "^6.2.5",
|
||||
"webextension-polyfill": "^0.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/svelte": "^1.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^3.9.1",
|
||||
"@typescript-eslint/parser": "^3.9.1",
|
||||
"copy-webpack-plugin": "^6.0.3",
|
||||
"css-loader": "^4.0.0",
|
||||
"eslint": "^7.7.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"@tsconfig/svelte": "^3.0.0",
|
||||
"@types/webextension-polyfill": "^0.8.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||
"@typescript-eslint/parser": "^5.20.0",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
"css-loader": "^6.7.1",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"html-loader": "^1.1.0",
|
||||
"html-webpack-plugin": "4.3.0",
|
||||
"html-loader": "^3.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"husky": ">=4",
|
||||
"lint-staged": ">=10",
|
||||
"prettier": "^2.0.5",
|
||||
"prettier-plugin-svelte": "^1.1.0",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"raw-loader": "^4.0.1",
|
||||
"sass": "^1.26.10",
|
||||
"sass-loader": "^9.0.2",
|
||||
"style-loader": "^1.2.1",
|
||||
"sass-loader": "^12.6.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"svelte": "^3.24.1",
|
||||
"svelte-check": "^1.0.11",
|
||||
"svelte-loader": "^2.13.6",
|
||||
"svelte-check": "^2.7.0",
|
||||
"svelte-loader": "^3.1.2",
|
||||
"svelte-preprocess": "^4.0.10",
|
||||
"ts-loader": "^8.0.1",
|
||||
"typescript": "^3.9.7",
|
||||
"web-ext": "^4.3.0",
|
||||
"webextension-polyfill-ts": "^0.19.0",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"worklet-loader": "^1.0.0",
|
||||
"zip-webpack-plugin": "^3.0.0"
|
||||
"ts-loader": "^9.2.8",
|
||||
"typescript": "^4.6.3",
|
||||
"web-ext": "^6.8.0",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"worklet-loader": "^2.0.0",
|
||||
"zip-webpack-plugin": "^4.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
|
@ -48,11 +50,6 @@
|
|||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*/**": [
|
||||
"eslint --fix ",
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
import { browser, Runtime } from "webextension-polyfill-ts";
|
||||
import { GTranslateScraper } from "./gtranslate_scraper";
|
||||
import browser, { type Runtime } from "webextension-polyfill";
|
||||
import { GTranslate } from "./translate";
|
||||
import { Flashcards } from "./database";
|
||||
import { BackgroundMessenger } from "../background_frontend_commands";
|
||||
import content_script from "../frontend/content_script/content_script.ts?file";
|
||||
|
||||
const con = new BackgroundMessenger();
|
||||
|
||||
const scraper = new GTranslateScraper();
|
||||
const scraper = new GTranslate();
|
||||
con.addMessageListener("translate", async (toTranslate, sender) => {
|
||||
return scraper.translate(
|
||||
toTranslate,
|
||||
await getCurrentLanguages(),
|
||||
sender!.tab?.id
|
||||
);
|
||||
return scraper.translate(toTranslate, await getCurrentLanguages());
|
||||
});
|
||||
|
||||
con.addMessageListener("getLanguages", () => scraper.languages);
|
||||
con.addMessageListener("getLanguages", () => scraper.get_languages());
|
||||
|
||||
const db = new Flashcards();
|
||||
window.flashcardDB = db;
|
||||
|
@ -23,7 +19,7 @@ con.addMessageListener("addFlashcard", (c) => db.addFlashcard(c));
|
|||
con.addMessageListener("removeFlashcard", (c) => db.removeFlashcard(c));
|
||||
|
||||
const getCurrentLanguages = async () => {
|
||||
const langs = await scraper.languages;
|
||||
const langs = await scraper.get_languages();
|
||||
const srcLangCode =
|
||||
(await browser.storage.local.get("srcLang"))["srcLang"] ?? "de";
|
||||
const dstLangCode =
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
import { browser, Runtime } from "webextension-polyfill-ts";
|
||||
import { Communicator, commandList, commandFunction } from "../communicator";
|
||||
import { newPromise } from "../utils";
|
||||
|
||||
interface BackgroundCommands extends commandList {
|
||||
translationFinished: TranslationMessage;
|
||||
languageList: LanguageListMessage;
|
||||
}
|
||||
|
||||
interface ContentScriptCommands extends commandList {
|
||||
translationRequest: TranslationRequest;
|
||||
}
|
||||
|
||||
interface TranslationMessage extends commandFunction {
|
||||
args: Translation;
|
||||
}
|
||||
|
||||
interface LanguageListMessage extends commandFunction {
|
||||
args: Array<Language>;
|
||||
}
|
||||
|
||||
interface TranslationRequest extends commandFunction {
|
||||
args: string;
|
||||
}
|
||||
|
||||
export class BackgroundMessenger extends Communicator<
|
||||
BackgroundCommands,
|
||||
ContentScriptCommands
|
||||
> {
|
||||
conn: Promise<Runtime.Port>;
|
||||
private resolvConn: (p: Runtime.Port) => void;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
[this.conn, this.resolvConn] = newPromise<Runtime.Port>();
|
||||
|
||||
browser.runtime.onConnect.addListener((p) => {
|
||||
if (p.name != "gtranslate_scraper_conn") return;
|
||||
this.resolvConn(p);
|
||||
p.onDisconnect.addListener(
|
||||
() => ([this.conn, this.resolvConn] = newPromise<Runtime.Port>())
|
||||
);
|
||||
p.onMessage.addListener((m) => this.onMessage(m, p.sender!));
|
||||
});
|
||||
}
|
||||
|
||||
async runCommand<K extends keyof ContentScriptCommands>(
|
||||
command: K,
|
||||
args: ContentScriptCommands[K]["args"]
|
||||
) {
|
||||
const msg = this.getCommandMessage(command, args);
|
||||
(await this.conn).postMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export class ContentScriptMessenger extends Communicator<
|
||||
ContentScriptCommands,
|
||||
BackgroundCommands
|
||||
> {
|
||||
conn: Runtime.Port;
|
||||
constructor() {
|
||||
super();
|
||||
this.conn = browser.runtime.connect({
|
||||
name: "gtranslate_scraper_conn",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any); //The declaration file is wrong
|
||||
this.conn.onMessage.addListener((m) => this.onMessage(m));
|
||||
}
|
||||
async runCommand<K extends keyof BackgroundCommands>(
|
||||
command: K,
|
||||
args: BackgroundCommands[K]["args"]
|
||||
) {
|
||||
const msg = this.getCommandMessage(command, args);
|
||||
return this.conn.postMessage(msg);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
import { ContentScriptMessenger } from "./gtranslate_commands";
|
||||
|
||||
(async () => {
|
||||
if (window.location.host != "translate.google.com" || window.hasRun) return;
|
||||
window.hasRun = true;
|
||||
|
||||
const conn = new ContentScriptMessenger();
|
||||
|
||||
const src = <HTMLTextAreaElement>document.querySelector("textarea#source");
|
||||
const result = <HTMLDivElement>(
|
||||
document.querySelector("div.results-container")
|
||||
);
|
||||
|
||||
const [srcLang, dstLang] = Array.from(
|
||||
document.querySelectorAll(".jfk-button-checked")
|
||||
).map((d) => ({
|
||||
code: d.getAttribute("value")!,
|
||||
name: d.textContent!,
|
||||
}));
|
||||
|
||||
const isTranslating = () => result.classList.contains("translating");
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
const wasTranslating = mutations.some((m) =>
|
||||
m.oldValue!.split(" ").some((c) => c == "translating")
|
||||
);
|
||||
if (wasTranslating && !isTranslating()) {
|
||||
sendTranslation();
|
||||
}
|
||||
});
|
||||
observer.observe(result, {
|
||||
attributes: true,
|
||||
attributeOldValue: true,
|
||||
attributeFilter: ["class"],
|
||||
});
|
||||
|
||||
const sendTranslation = () => {
|
||||
conn.runCommand("translationFinished", {
|
||||
src: src.value,
|
||||
result: result.innerText.trim(),
|
||||
languages: {
|
||||
srcLang: srcLang,
|
||||
dstLang: dstLang,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
conn.addMessageListener("translate", (toTranslate) => {
|
||||
if (src.value == toTranslate && !isTranslating()) sendTranslation();
|
||||
else src.value = toTranslate;
|
||||
});
|
||||
|
||||
const getLanguages = () => {
|
||||
const langs = document.querySelectorAll(
|
||||
"div.language_list_section:nth-child(3) > .language_list_item_wrapper"
|
||||
);
|
||||
return Array.from(langs).map((l) => {
|
||||
const code = l.classList[1].split("-").pop();
|
||||
const name = l.querySelector(".language_list_item_language_name")!
|
||||
.textContent;
|
||||
return { code: code!, name: name! };
|
||||
});
|
||||
};
|
||||
conn.runCommand("languageList", getLanguages());
|
||||
})();
|
|
@ -1,177 +0,0 @@
|
|||
import { browser, WebRequest } from "webextension-polyfill-ts";
|
||||
import content_script from "./gtranslate_content_script.ts?file";
|
||||
import { BackgroundMessenger } from "./gtranslate_commands";
|
||||
import { newPromise } from "../utils";
|
||||
|
||||
interface TranslationRequest {
|
||||
tabID?: number;
|
||||
resolveFn: (value: Translation) => void;
|
||||
rejectFn: (reason: string) => void;
|
||||
toTranslate: string;
|
||||
lang: LanguagePair;
|
||||
}
|
||||
|
||||
export class GTranslateScraper {
|
||||
private queue: Array<TranslationRequest> = [];
|
||||
private current?: TranslationRequest;
|
||||
private iframe = <HTMLIFrameElement>document.createElement("iframe");
|
||||
private current_lang: LanguagePair | undefined;
|
||||
|
||||
languages: Promise<Array<Language>>;
|
||||
msg: BackgroundMessenger;
|
||||
|
||||
constructor() {
|
||||
let languagesResolve: (value: Array<Language>) => void;
|
||||
[this.languages, languagesResolve] = newPromise<Array<Language>>();
|
||||
|
||||
this.msg = new BackgroundMessenger();
|
||||
this.msg.addMessageListener("languageList", languagesResolve);
|
||||
this.msg.addMessageListener("translationFinished", (trans) =>
|
||||
this.onTranslationRecieved(trans)
|
||||
);
|
||||
|
||||
//This allows us to create the google translate iframe by removing the x-frame-options header
|
||||
browser.webRequest.onHeadersReceived.addListener(
|
||||
allowIFrameAccess,
|
||||
{
|
||||
urls: ["https://translate.google.com/?*"],
|
||||
types: ["sub_frame"],
|
||||
},
|
||||
["blocking", "responseHeaders"]
|
||||
);
|
||||
|
||||
this.ChangeLanguage("de", "en"); //Sample languages so we can get the language list
|
||||
}
|
||||
|
||||
private async ChangeLanguage(
|
||||
srcLangCode: string,
|
||||
dstLangCode: string
|
||||
): Promise<void> {
|
||||
if (!document.body.contains(this.iframe))
|
||||
document.body.appendChild(this.iframe);
|
||||
|
||||
const [connectedPromise, onConnected] = newPromise<void>();
|
||||
|
||||
//Registers a temp content script, because we cannot inject scripts into iframes created on the background html page, because they have no tabId
|
||||
browser.contentScripts
|
||||
.register({
|
||||
matches: ["https://translate.google.com/?*"],
|
||||
allFrames: true,
|
||||
js: [
|
||||
{
|
||||
file: content_script,
|
||||
},
|
||||
],
|
||||
runAt: "document_end",
|
||||
})
|
||||
.then((r) => {
|
||||
this.iframe.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
r.unregister;
|
||||
this.msg.conn.then(() => onConnected());
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
this.iframe.src = `https://translate.google.com/?op=translate&sl=${srcLangCode}&tl=${dstLangCode}`;
|
||||
});
|
||||
|
||||
return connectedPromise;
|
||||
}
|
||||
|
||||
private onTranslationRecieved(trans: Translation) {
|
||||
if (this.current?.toTranslate !== trans.src)
|
||||
//I don't know how to code well so I gotta put in sanity checks like this to make debugging easier
|
||||
console.error(
|
||||
"Current request changed before OnTranslationRecieved was called. This should never happen"
|
||||
);
|
||||
if (this.current) this.current.resolveFn(trans);
|
||||
this.current = undefined;
|
||||
this.processFromQueue();
|
||||
}
|
||||
|
||||
private async processFromQueue() {
|
||||
if (this.current) return;
|
||||
this.current = this.queue.pop();
|
||||
if (!this.current) return;
|
||||
|
||||
this.processCurrent();
|
||||
}
|
||||
|
||||
private async processCurrent() {
|
||||
if (!this.current)
|
||||
throw new Error(
|
||||
"ProcessCurrent called while current translation request is undefined"
|
||||
);
|
||||
const cur = this.current;
|
||||
|
||||
let promise = Promise.resolve();
|
||||
if (this.current_lang != this.current.lang) {
|
||||
this.current_lang = cur.lang;
|
||||
|
||||
promise = this.ChangeLanguage(
|
||||
this.current_lang.srcLang.code,
|
||||
this.current_lang.dstLang.code
|
||||
);
|
||||
}
|
||||
await promise;
|
||||
if (cur == this.current) this.msg.runCommand("translate", cur.toTranslate);
|
||||
else
|
||||
throw new Error(
|
||||
"The current request changed while processCurrent was running. This should never happen"
|
||||
);
|
||||
}
|
||||
|
||||
async translate(
|
||||
toTranslate: string,
|
||||
langs: LanguagePair,
|
||||
tabID?: number
|
||||
): Promise<Translation> {
|
||||
toTranslate = toTranslate.trim();
|
||||
if (toTranslate == "")
|
||||
return Promise.resolve({
|
||||
src: "",
|
||||
result: "",
|
||||
languages: langs,
|
||||
});
|
||||
|
||||
const [promise, resolve, reject] = newPromise<Translation>();
|
||||
|
||||
const req = {
|
||||
toTranslate: toTranslate,
|
||||
resolveFn: resolve,
|
||||
rejectFn: reject,
|
||||
tabID: tabID,
|
||||
lang: langs,
|
||||
};
|
||||
//Remove the requests from the same tab
|
||||
if (tabID)
|
||||
this.queue = this.queue.filter((r) => {
|
||||
if (r.tabID !== tabID) {
|
||||
r.rejectFn("Got another request from the same tab");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
this.queue.push(req);
|
||||
|
||||
if (this.queue.length == 1 && !this.current) {
|
||||
this.current = this.queue.pop();
|
||||
await this.msg.conn;
|
||||
this.processCurrent();
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
const allowIFrameAccess = (info: WebRequest.OnHeadersReceivedDetailsType) => {
|
||||
//Make sure that only the background page can access this iframe
|
||||
if (info.documentUrl != document.URL) return;
|
||||
|
||||
let headers = info.responseHeaders;
|
||||
headers = headers?.filter((header) => {
|
||||
const h = header.name.toString().toLowerCase();
|
||||
h != "x-frame-options" && h != "frame-options";
|
||||
});
|
||||
return { responseHeaders: headers };
|
||||
};
|
42
src/background/translate.ts
Normal file
42
src/background/translate.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { newPromise } from "../utils";
|
||||
import googleTranslateApi from "@asmagin/google-translate-api";
|
||||
import translate from "@asmagin/google-translate-api";
|
||||
|
||||
const languages = googleTranslateApi.languages;
|
||||
|
||||
export abstract class Translator {
|
||||
abstract translate(
|
||||
toTranslate: string,
|
||||
langs: LanguagePair
|
||||
): Promise<Translation>;
|
||||
|
||||
abstract get_languages(): Promise<Language[]>;
|
||||
}
|
||||
|
||||
export class GTranslate extends Translator {
|
||||
async translate(
|
||||
toTranslate: string,
|
||||
langs: LanguagePair
|
||||
): Promise<Translation> {
|
||||
const resp = await translate(toTranslate, {
|
||||
from: langs.srcLang.code,
|
||||
to: langs.dstLang.code,
|
||||
});
|
||||
return {
|
||||
src: resp.from.text.value,
|
||||
languages: langs,
|
||||
result: resp.text,
|
||||
};
|
||||
}
|
||||
|
||||
async get_languages() {
|
||||
const res: Language[] = Object.keys(languages).map((k) => {
|
||||
const v = (languages as any)[k as any] as string;
|
||||
return {
|
||||
code: k,
|
||||
name: v,
|
||||
};
|
||||
});
|
||||
return Promise.resolve(res);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
import { Communicator, commandFunction, commandList } from "./communicator";
|
||||
import { browser } from "webextension-polyfill-ts";
|
||||
import {
|
||||
Communicator,
|
||||
type commandFunction,
|
||||
type commandList,
|
||||
} from "./communicator";
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
interface BackgroundCommands extends commandList {
|
||||
setEnabled: setEnabled;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type { Runtime } from "webextension-polyfill-ts";
|
||||
import type { Runtime } from "webextension-polyfill";
|
||||
|
||||
export interface commandFunction {
|
||||
args: any;
|
||||
|
@ -29,7 +29,7 @@ export abstract class Communicator<
|
|||
listener<RecvCommands, keyof RecvCommands>
|
||||
>();
|
||||
|
||||
abstract async runCommand<K extends keyof SendCommands>(
|
||||
abstract runCommand<K extends keyof SendCommands>(
|
||||
command: K,
|
||||
args: SendCommands[K]["args"],
|
||||
...rest: unknown[]
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
card
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
import type { Flashcards } from "../../background/database";
|
||||
export let cardID: IDBValidKey;
|
||||
|
||||
const flashcardDB = getContext<Flashcards>("flashcardDB");
|
||||
$: cardPromise = flashcardDB.getCard(cardID);
|
||||
const flashcardDB = getContext<Promise<Flashcards>>("flashcardDB");
|
||||
$: cardPromise = flashcardDB.then((db) => db.getCard(cardID));
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
|
@ -36,7 +36,7 @@
|
|||
padding: 1em;
|
||||
margin: 0.1em;
|
||||
height: 100%;
|
||||
width: calc(100%-1vw);
|
||||
width: calc(100% - 1vw);
|
||||
background-color: var(--background-color-3);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { browser } from "webextension-polyfill-ts";
|
||||
import browser from "webextension-polyfill";
|
||||
import { setContext } from "svelte";
|
||||
import VirtualList from "@sveltejs/svelte-virtual-list";
|
||||
import VirtualList from "@sveltejs/svelte-virtual-list/VirtualList.svelte";
|
||||
import Flashcard from "./Flashcard.svelte";
|
||||
/*
|
||||
const onCardChange = (card: Flashcard, change: "added" | "removed") => {
|
||||
|
@ -19,14 +19,15 @@
|
|||
*/
|
||||
|
||||
let cards: IDBValidKey[] = [];
|
||||
const flashcardDBPromise = browser.runtime
|
||||
.getBackgroundPage()
|
||||
.then((bp) => bp.flashcardDB);
|
||||
setContext("flashcardDB", flashcardDBPromise);
|
||||
(async () => {
|
||||
const backgroundPage = await browser.runtime.getBackgroundPage();
|
||||
const flashcardDB = backgroundPage.flashcardDB;
|
||||
const flashcardDB = await flashcardDBPromise;
|
||||
cards = await flashcardDB.getAllKeys();
|
||||
//flashcardDB.addChangeCallback(onCardChange);
|
||||
//window.addEventListener("beforeunload", () => flashcardDB.removeChangeCallback(onCardChange));
|
||||
|
||||
setContext("flashcardDB", flashcardDB);
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<script lang="ts">
|
||||
import Select from "svelte-select";
|
||||
import Select from "svelte-select/src/Select.svelte";
|
||||
export let langs: Array<Language>;
|
||||
export let selectedValue: Language;
|
||||
$: console.log(selectedValue);
|
||||
|
||||
const getLabel = (o: Language) => o.name;
|
||||
const itemFilter = (label: string, filterText: string) =>
|
||||
label.toLowerCase().startsWith(filterText.toLowerCase());
|
||||
</script>
|
||||
|
||||
<div class="select-styling">
|
||||
|
@ -14,9 +13,9 @@
|
|||
getOptionLabel={getLabel}
|
||||
getSelectionLabel={getLabel}
|
||||
optionIdentifier="code"
|
||||
{itemFilter}
|
||||
isClearable={false}
|
||||
bind:selectedValue />
|
||||
bind:value={selectedValue}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
</script>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<label class:enabled>
|
||||
<input type="checkbox" bind:checked={enabled} />
|
||||
{enabled ? 'Disable Extension' : 'Enable Extension'}
|
||||
{enabled ? "Disable Extension" : "Enable Extension"}
|
||||
</label>
|
||||
|
||||
{#if selected}
|
||||
|
|
1
src/global.d.ts
vendored
Normal file
1
src/global.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/// <reference types="svelte" />
|
|
@ -6,6 +6,5 @@
|
|||
"target": "ES6",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["src/**/*", "src/node_modules"],
|
||||
"exclude": ["node_modules/*"]
|
||||
"include": ["/**/*"]
|
||||
}
|
|
@ -61,6 +61,13 @@ let options = {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// required to prevent errors from Svelte on Webpack 5+, omit on Webpack 4
|
||||
test: /node_modules\/svelte\/.*\.mjs$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
|
|
Loading…
Reference in a new issue