From 9c2ade8505fd5696db111a72c46ce746f39a37ee Mon Sep 17 00:00:00 2001 From: Petr Stepchenko Date: Fri, 11 Aug 2023 17:59:36 +0200 Subject: [PATCH] Add word translation modal --- src/assets/style/content/global.scss | 3 +- .../style/content/word-translation.scss | 37 +++++++---- src/learning-service/anki.ts | 4 +- src/learning-service/learningService.ts | 6 +- src/learning-service/linguaLeo.ts | 4 +- src/learning-service/puzzleEnglish.ts | 4 +- .../Subs/PhrasalVerbTranslation.tsx | 62 ++++++++++++++++++ .../components/Subs/SubItemTranslation.tsx | 65 +++++++------------ src/pages/content/components/Subs/Subs.tsx | 11 +--- src/utils/findPhrasalVerbs.ts | 1 - src/utils/getLearningService.ts | 16 +++++ 11 files changed, 143 insertions(+), 70 deletions(-) create mode 100644 src/pages/content/components/Subs/PhrasalVerbTranslation.tsx create mode 100644 src/utils/getLearningService.ts diff --git a/src/assets/style/content/global.scss b/src/assets/style/content/global.scss index 80ecac0..d336683 100644 --- a/src/assets/style/content/global.scss +++ b/src/assets/style/content/global.scss @@ -58,7 +58,7 @@ transform: translate3d(-50%, -100%, 0); background-color: #1e1e1e; border-radius: 0.4em; - font-size: 16px; + font-size: 18px; width: 100%; font-style: normal; white-space: normal; @@ -67,6 +67,7 @@ padding: 16px 24px; box-sizing: border-box; white-space: pre-wrap; + text-wrap: balance; &:after { content: ""; diff --git a/src/assets/style/content/word-translation.scss b/src/assets/style/content/word-translation.scss index cc6f33e..959f4c7 100644 --- a/src/assets/style/content/word-translation.scss +++ b/src/assets/style/content/word-translation.scss @@ -1,6 +1,7 @@ .es-word-translation { width: max-content; max-width: 360px; + min-width: 200px; text-align: left; position: absolute; top: 0px; @@ -67,30 +68,44 @@ .es-translation-variants { margin: 12px 0; font-size: 14px; - - table { - border-collapse: separate; - border-spacing: 0 4px; - } + display: grid; + grid-template-columns: fit-content(120px) auto 1fr; + column-gap: 16px; + row-gap: 4px; + align-items: center; } -.es-translation-variant { - svg { - vertical-align: middle; - } +.es-translation-phrasal-verbs-variants { + display: flex; + flex-direction: column; + gap: 4px; + font-size: 14px; + margin: 12px 0; } .es-translation-variant-word { - max-width: 120px; + hyphens: auto; + display: flex; + align-items: center; + + .es-settings-button { + flex: 0 0 14px; + + svg { + vertical-align: middle; + width: 100%; + padding-bottom: 2px; + } + } } .es-translation-variant-part-of-speach { text-align: left; color: #737373; - padding: 0 16px; } .es-translation-variant-synonyms { + width: fit-content; color: #bbbbbb; flex: 1; } diff --git a/src/learning-service/anki.ts b/src/learning-service/anki.ts index 575e26d..65606a2 100644 --- a/src/learning-service/anki.ts +++ b/src/learning-service/anki.ts @@ -1,4 +1,4 @@ -import ILearningService from "./learningService"; +import ILearningService, { TAditionalData } from "./learningService"; const ANKI_API_VERSION = 6; const ANKI_DESK = "Easysubs"; @@ -11,7 +11,7 @@ export class Anki implements ILearningService { this.color = "#0d6efd"; } - public async addWord(word: string, translation: string, aditionalData: Record): Promise { + public async addWord(word: string, translation: string, aditionalData: TAditionalData): Promise { const createDeskResult = await chrome.runtime.sendMessage({ type: "post", url: ANKI_URL, diff --git a/src/learning-service/learningService.ts b/src/learning-service/learningService.ts index a3765fc..a0dcd0a 100644 --- a/src/learning-service/learningService.ts +++ b/src/learning-service/learningService.ts @@ -1,6 +1,10 @@ +export type TAditionalData = { + context?: string; + partOfSpeech?: string; +}; interface ILearningService { color: string; - addWord: (word: string, translation: string, aditionalData: Record) => Promise; + addWord: (word: string, translation: string, aditionalData: TAditionalData) => Promise; } export default ILearningService; diff --git a/src/learning-service/linguaLeo.ts b/src/learning-service/linguaLeo.ts index 5ccf678..ea9abd1 100644 --- a/src/learning-service/linguaLeo.ts +++ b/src/learning-service/linguaLeo.ts @@ -1,4 +1,4 @@ -import ILearningService from "./learningService"; +import ILearningService, { TAditionalData } from "./learningService"; export class LinguaLeo implements ILearningService { public color: string; @@ -7,7 +7,7 @@ export class LinguaLeo implements ILearningService { this.color = "#FFC900"; } - public async addWord(word: string, translation: string, aditionalData: Record): Promise { + public async addWord(word: string, translation: string, aditionalData: TAditionalData): Promise { const url = new URL("https://api.lingualeo.com/addword"); const data = { word: word, diff --git a/src/learning-service/puzzleEnglish.ts b/src/learning-service/puzzleEnglish.ts index a0dab83..de5dcca 100644 --- a/src/learning-service/puzzleEnglish.ts +++ b/src/learning-service/puzzleEnglish.ts @@ -1,4 +1,4 @@ -import ILearningService from "./learningService"; +import ILearningService, { TAditionalData } from "./learningService"; export class PuzzleEnglish implements ILearningService { public color: string; @@ -7,7 +7,7 @@ export class PuzzleEnglish implements ILearningService { this.color = "#88BA28"; } - public async addWord(word: string, translation: string, aditionalData: Record): Promise { + public async addWord(word: string, translation: string, aditionalData: TAditionalData): Promise { const url = "https://puzzle-english.com/api2/userDictionary/addWord"; const data = { post_id: 0, diff --git a/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx b/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx new file mode 100644 index 0000000..1923e1b --- /dev/null +++ b/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx @@ -0,0 +1,62 @@ +import { FC, useEffect, useState } from "react"; +import { useUnit } from "effector-react"; + +import { TPhrasalVerb } from "@src/models/types"; +import { cleanWordTranslation, requestWordTranslation } from "@src/models/translations"; +import { $learningService } from "@src/models/settings"; +import { $subsLanguage } from "@src/models/subs"; +import ILearningService from "@src/learning-service/learningService"; +import { getLearningService } from "@src/utils/getLearningService"; +import toast from "react-hot-toast"; +import { PlusIcon } from "./assets/PlusIcon"; + +export const PhrasalVerbTranslation: FC<{ phrasalVerb: TPhrasalVerb }> = ({ phrasalVerb }) => { + const [learningService] = useUnit([$learningService, requestWordTranslation, cleanWordTranslation, $subsLanguage]); + + const [service, setService] = useState(null); + + useEffect(() => { + setService(getLearningService(learningService)); + }, [learningService]); + + const handleAddWord = (word: string, translation: string) => { + if (service) { + service + .addWord(word.toLowerCase(), translation, { partOfSpeech: "phrase" }) + .then((value) => { + toast.success(value); + }) + .catch((error) => { + toast.error(error); + }); + } + }; + + return ( +
+
{phrasalVerb.text}
+
+
+
phrasal verb
+
+
+ {phrasalVerb.translations.map((translation) => ( +
+ {service && ( + + )} + {translation} +
+ ))} +
+
+ ); +}; diff --git a/src/pages/content/components/Subs/SubItemTranslation.tsx b/src/pages/content/components/Subs/SubItemTranslation.tsx index 2c49da0..c3a39f0 100644 --- a/src/pages/content/components/Subs/SubItemTranslation.tsx +++ b/src/pages/content/components/Subs/SubItemTranslation.tsx @@ -3,9 +3,6 @@ import { useUnit } from "effector-react"; import { $learningService } from "@src/models/settings"; import { $currentWordTranslation, cleanWordTranslation, requestWordTranslation } from "@src/models/translations"; -import { Anki } from "@src/learning-service/anki"; -import { LinguaLeo } from "@src/learning-service/linguaLeo"; -import { PuzzleEnglish } from "@src/learning-service/puzzleEnglish"; import toast from "react-hot-toast"; import { SoundIcon } from "./assets/SoundIcon"; import { PlusIcon } from "./assets/PlusIcon"; @@ -18,6 +15,7 @@ import youglishIcon from "@assets/img/icons/youglish.png"; import ILearningService from "@src/learning-service/learningService"; import { TWordTranslationItem } from "@src/models/types"; import { $subsLanguage } from "@src/models/subs"; +import { getLearningService } from "@src/utils/getLearningService"; export const SubItemTranslation: FC<{ text: string }> = ({ text }) => { const [ @@ -31,15 +29,7 @@ export const SubItemTranslation: FC<{ text: string }> = ({ text }) => { const [service, setService] = useState(null); useEffect(() => { - if (learningService === "anki") { - setService(new Anki()); - } - if (learningService === "lingualeo") { - setService(new LinguaLeo()); - } - if (learningService === "puzzle-english") { - setService(new PuzzleEnglish()); - } + setService(getLearningService(learningService)); }, [learningService]); useEffect(() => { @@ -53,10 +43,10 @@ export const SubItemTranslation: FC<{ text: string }> = ({ text }) => { return null; } - const handleAddWord = (wors: string, translation: TWordTranslationItem) => { + const handleAddWord = (word: string, translation: TWordTranslationItem) => { if (service) { service - .addWord(wors.toLowerCase(), translation.word, {}) + .addWord(word.toLowerCase(), translation.word, { partOfSpeech: translation.partOfSpeech }) .then((value) => { toast.success(value); }) @@ -76,37 +66,32 @@ export const SubItemTranslation: FC<{ text: string }> = ({ text }) => {
{text.toLowerCase()}
- {currentWordTranslation.transcription &&
/{currentWordTranslation.transcription}/
}
- - - {currentWordTranslation.translations.length > 0 && - currentWordTranslation.translations.map((translation) => ( - - {service && ( - - )} - - - - - ))} - -
- - {translation.word}{translation.partOfSpeech}{joinTranslations(translation.synonyms)}
+ {currentWordTranslation.translations.length > 0 && + currentWordTranslation.translations.map((translation) => ( + <> +
+ {service && ( + + )} +
{translation.word}
+
+
{translation.partOfSpeech}
+
{joinTranslations(translation.synonyms)}
+ + ))}
{subsLanguage === "en" && ( <> diff --git a/src/pages/content/components/Subs/Subs.tsx b/src/pages/content/components/Subs/Subs.tsx index 84481ea..db78678 100644 --- a/src/pages/content/components/Subs/Subs.tsx +++ b/src/pages/content/components/Subs/Subs.tsx @@ -11,6 +11,7 @@ import { addKeyboardEventsListeners, removeKeyboardEventsListeners } from "@src/ import { findPhrasalVerbs } from "@src/utils/findPhrasalVerbs"; import { joinTranslations } from "@src/utils/joinTranslations"; import { SubItemTranslation } from "./SubItemTranslation"; +import { PhrasalVerbTranslation } from "./PhrasalVerbTranslation"; type TSubsProps = {}; @@ -159,16 +160,6 @@ const SubItem: FC = ({ subItem, phrasalVerbs, index }) => { ); }; -const PhrasalVerbTranslation: FC<{ phrasalVerb: TPhrasalVerb }> = ({ phrasalVerb }) => { - return ( -
-
{phrasalVerb.text}
-
-
{joinTranslations(phrasalVerb.translations)}
-
- ); -}; - const SubFullTranslation: FC<{ text: string }> = ({ text }) => { const [currentSubTranslation, handleRequestSubTranslation, handleCleanSubTranslation] = useUnit([ $currentSubTranslation, diff --git a/src/utils/findPhrasalVerbs.ts b/src/utils/findPhrasalVerbs.ts index 09f8a13..a84af22 100644 --- a/src/utils/findPhrasalVerbs.ts +++ b/src/utils/findPhrasalVerbs.ts @@ -9,7 +9,6 @@ export const findPhrasalVerbs = (text: string): TPhrasalVerb[] => { Object.entries(PHRASAL_VERBS).forEach(([key, item]) => { const phrasalVerbList: string[] = [key, ...(item["derivatives"] ?? [])]; - for (const phrasalVerb of phrasalVerbList) { const phrasalVerbWords = phrasalVerb.match(/[^ ]+/g); if (words.includes(phrasalVerbWords[0])) { diff --git a/src/utils/getLearningService.ts b/src/utils/getLearningService.ts new file mode 100644 index 0000000..8400d1a --- /dev/null +++ b/src/utils/getLearningService.ts @@ -0,0 +1,16 @@ +import { Anki } from "@src/learning-service/anki"; +import { LinguaLeo } from "@src/learning-service/linguaLeo"; +import { PuzzleEnglish } from "@src/learning-service/puzzleEnglish"; +import { TLearningService } from "@src/models/types"; + +export const getLearningService = (learningService: TLearningService) => { + if (learningService === "anki") { + return new Anki(); + } + if (learningService === "lingualeo") { + return new LinguaLeo(); + } + if (learningService === "puzzle-english") { + return new PuzzleEnglish(); + } +};