Options page
This commit is contained in:
parent
5451b3713e
commit
9ede15c7b3
11 changed files with 119 additions and 39 deletions
|
@ -4,6 +4,8 @@
|
||||||
"description": "Lingo is a small browser extension to help you learn languages",
|
"description": "Lingo is a small browser extension to help you learn languages",
|
||||||
"main": "webpack.config.js",
|
"main": "webpack.config.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sveltejs/svelte-virtual-list": "^3.0.1",
|
||||||
|
"svelte-feather-icons": "^3.2.2",
|
||||||
"svelte-select": "^3.11.0",
|
"svelte-select": "^3.11.0",
|
||||||
"tippy.js": "^6.2.5"
|
"tippy.js": "^6.2.5"
|
||||||
},
|
},
|
||||||
|
@ -52,6 +54,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*/**": ["eslint --fix ","prettier --write"]
|
"*/**": [
|
||||||
|
"eslint --fix ",
|
||||||
|
"prettier --write"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,13 @@ import content_script from "../frontend/content_script/content_script.ts?file";
|
||||||
const con = new BackgroundMessenger();
|
const con = new BackgroundMessenger();
|
||||||
|
|
||||||
const scraper = new GTranslateScraper();
|
const scraper = new GTranslateScraper();
|
||||||
con.addMessageListener("translate", async (toTranslate, sender) =>
|
con.addMessageListener("translate", async (toTranslate, sender) => {
|
||||||
scraper.translate(toTranslate, await getCurrentLanguages(), sender!.tab?.id)
|
return scraper.translate(
|
||||||
);
|
toTranslate,
|
||||||
|
await getCurrentLanguages(),
|
||||||
|
sender!.tab?.id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
con.addMessageListener("getLanguages", () => scraper.languages);
|
con.addMessageListener("getLanguages", () => scraper.languages);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import { newPromise } from "../utils";
|
import { newPromise } from "../utils";
|
||||||
|
|
||||||
|
type flashcardChangedCallback = (
|
||||||
|
card: Flashcard,
|
||||||
|
change: "added" | "removed"
|
||||||
|
) => void;
|
||||||
export class Flashcards {
|
export class Flashcards {
|
||||||
db: Promise<IDBDatabase>;
|
db: Promise<IDBDatabase>;
|
||||||
|
private callbacks: flashcardChangedCallback[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const [promise, resolve, reject] = newPromise<IDBDatabase>();
|
const [promise, resolve, reject] = newPromise<IDBDatabase>();
|
||||||
|
@ -28,8 +33,8 @@ export class Flashcards {
|
||||||
}
|
}
|
||||||
|
|
||||||
async addFlashcard(t: Translation | Flashcard): Promise<Flashcard> {
|
async addFlashcard(t: Translation | Flashcard): Promise<Flashcard> {
|
||||||
let card: Flashcard;
|
let card: Omit<Flashcard, "id"> & { id?: IDBValidKey };
|
||||||
if ("dateAdded" in t && "exported" in t) card = t;
|
if ("id" in t) card = t;
|
||||||
else {
|
else {
|
||||||
card = {
|
card = {
|
||||||
...t,
|
...t,
|
||||||
|
@ -41,11 +46,16 @@ export class Flashcards {
|
||||||
const req = (await this.db)
|
const req = (await this.db)
|
||||||
.transaction(["flashcards"], "readwrite")
|
.transaction(["flashcards"], "readwrite")
|
||||||
.objectStore("flashcards")
|
.objectStore("flashcards")
|
||||||
.add(card);
|
.put(card);
|
||||||
|
|
||||||
const [promise, resolve, reject] = newPromise<Flashcard>();
|
const [promise, resolve, reject] = newPromise<Flashcard>();
|
||||||
req.onsuccess = () => {
|
req.onsuccess = () => {
|
||||||
card.id = req.result;
|
const newCard = {
|
||||||
resolve(card);
|
id: req.result,
|
||||||
|
...card,
|
||||||
|
};
|
||||||
|
resolve(newCard);
|
||||||
|
this.callbacks.forEach((c) => c(newCard, "added"));
|
||||||
};
|
};
|
||||||
req.onerror = () => reject(req.error);
|
req.onerror = () => reject(req.error);
|
||||||
return promise;
|
return promise;
|
||||||
|
@ -59,7 +69,21 @@ export class Flashcards {
|
||||||
.delete(card.id);
|
.delete(card.id);
|
||||||
|
|
||||||
const [promise, resolve, reject] = newPromise<void>();
|
const [promise, resolve, reject] = newPromise<void>();
|
||||||
req.onsuccess = () => resolve();
|
req.onsuccess = () => {
|
||||||
|
resolve();
|
||||||
|
this.callbacks.forEach((c) => c(card, "removed"));
|
||||||
|
};
|
||||||
|
req.onerror = () => reject(req.error);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
async getCard(cardID: IDBValidKey): Promise<Flashcard | undefined> {
|
||||||
|
const req = (await this.db)
|
||||||
|
.transaction(["flashcards"], "readonly")
|
||||||
|
.objectStore("flashcards")
|
||||||
|
.get(cardID);
|
||||||
|
|
||||||
|
const [promise, resolve, reject] = newPromise<Flashcard | undefined>();
|
||||||
|
req.onsuccess = () => resolve(req.result);
|
||||||
req.onerror = () => reject(req.error);
|
req.onerror = () => reject(req.error);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
@ -75,4 +99,48 @@ export class Flashcards {
|
||||||
req.onerror = () => reject(req.error);
|
req.onerror = () => reject(req.error);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllKeys(): Promise<IDBValidKey[]> {
|
||||||
|
const req = (await this.db)
|
||||||
|
.transaction(["flashcards"], "readonly")
|
||||||
|
.objectStore("flashcards")
|
||||||
|
.getAllKeys();
|
||||||
|
|
||||||
|
const [promise, resolve, reject] = newPromise<IDBValidKey[]>();
|
||||||
|
req.onsuccess = () => resolve(req.result);
|
||||||
|
req.onerror = () => reject(req.error);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCardFromTransRequest(src: string, language: LanguagePair) {
|
||||||
|
const [promise, resolve, reject] = newPromise<Flashcard | undefined>();
|
||||||
|
|
||||||
|
const req = (await this.db)
|
||||||
|
.transaction(["flashcards"], "readonly")
|
||||||
|
.objectStore("flashcards")
|
||||||
|
.index("src")
|
||||||
|
.openCursor(IDBKeyRange.only(src));
|
||||||
|
req.onsuccess = () => {
|
||||||
|
const cursor = req.result;
|
||||||
|
const res = cursor?.value as Flashcard | undefined;
|
||||||
|
|
||||||
|
if (
|
||||||
|
res?.languages?.srcLang?.code == language.srcLang.code &&
|
||||||
|
res?.languages?.dstLang?.code == language.dstLang.code
|
||||||
|
)
|
||||||
|
resolve(res);
|
||||||
|
else if (cursor) cursor.continue();
|
||||||
|
else resolve(undefined);
|
||||||
|
};
|
||||||
|
req.onerror = reject;
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
addChangeCallback(callback: flashcardChangedCallback) {
|
||||||
|
this.callbacks.push(callback);
|
||||||
|
console.log(this.callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChangeCallback(callback: flashcardChangedCallback) {
|
||||||
|
this.callbacks = this.callbacks.filter((f) => f != callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface getLanguages extends commandFunction {
|
||||||
|
|
||||||
interface translate extends commandFunction {
|
interface translate extends commandFunction {
|
||||||
args: string;
|
args: string;
|
||||||
return: Translation;
|
return: Promise<Translation | Flashcard>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface getCurrentLanguages extends commandFunction {
|
interface getCurrentLanguages extends commandFunction {
|
||||||
|
@ -80,7 +80,7 @@ export class FrontendMessenger extends Communicator<
|
||||||
runCommand<K extends keyof BackgroundCommands>(
|
runCommand<K extends keyof BackgroundCommands>(
|
||||||
command: K,
|
command: K,
|
||||||
args: BackgroundCommands[K]["args"]
|
args: BackgroundCommands[K]["args"]
|
||||||
): BackgroundCommands[K]["return"] {
|
): Promise<BackgroundCommands[K]["return"]> {
|
||||||
const message = this.getCommandMessage(command, args);
|
const message = this.getCommandMessage(command, args);
|
||||||
return browser.runtime.sendMessage(message);
|
return browser.runtime.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
5
src/file.d.ts
vendored
5
src/file.d.ts
vendored
|
@ -2,3 +2,8 @@ declare module "*?file" {
|
||||||
const file: string;
|
const file: string;
|
||||||
export = file;
|
export = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module "*.svg" {
|
||||||
|
const file: string;
|
||||||
|
export = file;
|
||||||
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
import type { FrontendMessenger } from "../../background_frontend_commands";
|
import type { FrontendMessenger } from "../../background_frontend_commands";
|
||||||
|
|
||||||
let connection = getContext("connection") as FrontendMessenger;
|
let connection = getContext("connection") as FrontendMessenger;
|
||||||
export let trans: Translation;
|
export let trans: Translation | Flashcard;
|
||||||
let card: Flashcard | undefined;
|
let card: Flashcard | undefined;
|
||||||
|
|
||||||
|
$: if ("id" in trans) card = trans;
|
||||||
const addFlashcard = async () => {
|
const addFlashcard = async () => {
|
||||||
card = await connection.runCommand("addFlashcard", trans);
|
card = await connection.runCommand("addFlashcard", trans);
|
||||||
};
|
};
|
||||||
|
@ -26,7 +27,7 @@
|
||||||
card
|
card
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
<button on:click={removeFlashcard} class="enabled">
|
<button on:click={removeFlashcard} class="remove">
|
||||||
Remove
|
Remove
|
||||||
<br />
|
<br />
|
||||||
card
|
card
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "../color_scheme";
|
@use "../color_scheme";
|
||||||
|
@use "../common";
|
||||||
|
|
||||||
.translatedContainer {
|
.translatedContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -48,23 +50,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
@include common.button;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
border: 0;
|
border: 0;
|
||||||
min-width: 9ch;
|
min-width: 9ch;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
||||||
cursor: pointer;
|
@include common.button_green;
|
||||||
background-color: var(--green-1);
|
&.remove {
|
||||||
&:hover {
|
@include common.button_red;
|
||||||
background-color: var(--green-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.enabled {
|
|
||||||
background-color: var(--red-1);
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--red-2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "../color_scheme.scss";
|
@use "../color_scheme";
|
||||||
|
@use "../common";
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
|
@include common.button;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -61,17 +63,9 @@
|
||||||
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
cursor: pointer;
|
@include common.button_green;
|
||||||
background-color: var(--green-1);
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--green-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.enabled {
|
&.enabled {
|
||||||
background-color: var(--red-1);
|
@include common.button_red;
|
||||||
&:hover {
|
|
||||||
background-color: var(--red-2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -8,7 +8,7 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Flashcard {
|
interface Flashcard {
|
||||||
id?: IDBValidKey;
|
id: IDBValidKey;
|
||||||
src: string;
|
src: string;
|
||||||
result: string;
|
result: string;
|
||||||
dateAdded: Date;
|
dateAdded: Date;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
type resolveCallback<T> = (value: T) => void;
|
type resolveCallback<T> = (value: T) => void;
|
||||||
type rejectCallback = (reason: unknown) => void;
|
type rejectCallback = (reason?: unknown) => void;
|
||||||
|
|
||||||
export const newPromise = <T>(): [
|
export const newPromise = <T>(): [
|
||||||
Promise<T>,
|
Promise<T>,
|
||||||
|
|
|
@ -54,7 +54,6 @@ let options = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(html|svelte)$/,
|
test: /\.(html|svelte)$/,
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
use: {
|
||||||
loader: "svelte-loader",
|
loader: "svelte-loader",
|
||||||
options: {
|
options: {
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -112,6 +112,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||||
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
|
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
|
||||||
|
|
||||||
|
"@sveltejs/svelte-virtual-list@^3.0.1":
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sveltejs/svelte-virtual-list/-/svelte-virtual-list-3.0.1.tgz#3784d6426508836b4471bba8ba293430e73717d8"
|
||||||
|
integrity sha512-aF9TptS7NKKS7/TqpsxQBSDJ9Q0XBYzBehCeIC5DzdMEgrJZpIYao9LRLnyyo6SVodpapm2B7FE/Lj+FSA5/SQ==
|
||||||
|
|
||||||
"@szmarczak/http-timer@^1.1.2":
|
"@szmarczak/http-timer@^1.1.2":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
|
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
|
||||||
|
@ -6195,6 +6200,11 @@ svelte-dev-helper@^1.1.9:
|
||||||
resolved "https://registry.yarnpkg.com/svelte-dev-helper/-/svelte-dev-helper-1.1.9.tgz#7d187db5c6cdbbd64d75a32f91b8998bde3273c3"
|
resolved "https://registry.yarnpkg.com/svelte-dev-helper/-/svelte-dev-helper-1.1.9.tgz#7d187db5c6cdbbd64d75a32f91b8998bde3273c3"
|
||||||
integrity sha1-fRh9tcbNu9ZNdaMvkbiZi94yc8M=
|
integrity sha1-fRh9tcbNu9ZNdaMvkbiZi94yc8M=
|
||||||
|
|
||||||
|
svelte-feather-icons@^3.2.2:
|
||||||
|
version "3.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-feather-icons/-/svelte-feather-icons-3.2.2.tgz#fdb4ecc7ac9127442d06d8bbeee52d3be0491834"
|
||||||
|
integrity sha512-GY86mGZYjZCRRnY2t5caiY+2gzSWrYvG8dUjhnOi6YlaWVZEAzDOBuTDiZ1abOz2mM9fCpdpbgj1JZajjzEEAw==
|
||||||
|
|
||||||
svelte-language-server@*:
|
svelte-language-server@*:
|
||||||
version "0.10.90"
|
version "0.10.90"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-language-server/-/svelte-language-server-0.10.90.tgz#888d1371f0ea8ba2d9bf56da8f086ce0de1df60f"
|
resolved "https://registry.yarnpkg.com/svelte-language-server/-/svelte-language-server-0.10.90.tgz#888d1371f0ea8ba2d9bf56da8f086ce0de1df60f"
|
||||||
|
|
Loading…
Reference in a new issue