From fa74e4722b5d666a16f118f31da3e9764c7cb5bc Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 01:27:18 +0400 Subject: [PATCH 01/12] chore: add dictionary card --- .../ui/DictionaryCard/DictionaryCard.tsx | 21 ++++++++ .../dictionary/ui/DictionaryCard/index.ts | 1 + .../ui/DictionaryCard/styles.module.scss | 48 +++++++++++++++++++ src/entities/dictionary/ui/index.ts | 1 + 4 files changed, 71 insertions(+) create mode 100644 src/entities/dictionary/ui/DictionaryCard/DictionaryCard.tsx create mode 100644 src/entities/dictionary/ui/DictionaryCard/index.ts create mode 100644 src/entities/dictionary/ui/DictionaryCard/styles.module.scss create mode 100644 src/entities/dictionary/ui/index.ts diff --git a/src/entities/dictionary/ui/DictionaryCard/DictionaryCard.tsx b/src/entities/dictionary/ui/DictionaryCard/DictionaryCard.tsx new file mode 100644 index 0000000..50d50e5 --- /dev/null +++ b/src/entities/dictionary/ui/DictionaryCard/DictionaryCard.tsx @@ -0,0 +1,21 @@ +import { JSXInternal } from 'node_modules/preact/src/jsx' + +import styles from './styles.module.scss' + +interface Props { + url: string + name: string + actions?: JSXInternal.Element +} + +export const DictionaryCard = ({ url, name, actions }: Props) => ( +
  • + + +
    + {name} +
    + +
    {actions}
    +
  • +) diff --git a/src/entities/dictionary/ui/DictionaryCard/index.ts b/src/entities/dictionary/ui/DictionaryCard/index.ts new file mode 100644 index 0000000..d62a3ef --- /dev/null +++ b/src/entities/dictionary/ui/DictionaryCard/index.ts @@ -0,0 +1 @@ +export { DictionaryCard } from './DictionaryCard' diff --git a/src/entities/dictionary/ui/DictionaryCard/styles.module.scss b/src/entities/dictionary/ui/DictionaryCard/styles.module.scss new file mode 100644 index 0000000..aab72e0 --- /dev/null +++ b/src/entities/dictionary/ui/DictionaryCard/styles.module.scss @@ -0,0 +1,48 @@ +.dictionary { + position: relative; + display: flex; + flex-direction: column; + gap: var(--spacing-1); + padding: var(--spacing-6); + border: 1px solid var(--color-neutral-200); + border-radius: var(--radius-1); + transition: + outline-color 0.25s, + border-color 0.25s; + + &:hover { + border-color: var(--color-brand-700); + outline: 1px solid var(--color-brand-700); + } + + &__title { + padding-block: var(--spacing-1); + word-break: break-word; + overflow-wrap: break-word; + } + + &__url { + position: absolute; + top: 0; + left: 0; + z-index: 2; + width: 100%; + height: 100%; + cursor: pointer; + border-radius: var(--radius-1); + transition: outline-color 0.025s; + + &:focus-visible { + border-color: var(--color-brand-700); + outline: var(--outline) solid var(--color-brand-700); + } + } + + &__actions { + position: relative; + z-index: 3; + display: flex; + flex-direction: column; + gap: var(--spacing-1); + } +} diff --git a/src/entities/dictionary/ui/index.ts b/src/entities/dictionary/ui/index.ts new file mode 100644 index 0000000..b6fffcf --- /dev/null +++ b/src/entities/dictionary/ui/index.ts @@ -0,0 +1 @@ +export * from './DictionaryCard' From 6d8434bc02bd696536dac58a2b5cd3026fc2ea0a Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 01:28:11 +0400 Subject: [PATCH 02/12] chore: add no selected languages placeholder --- .../language/SelectLanguages/ui/NoSelectedLanguages.tsx | 5 +++++ src/features/language/SelectLanguages/ui/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/features/language/SelectLanguages/ui/NoSelectedLanguages.tsx diff --git a/src/features/language/SelectLanguages/ui/NoSelectedLanguages.tsx b/src/features/language/SelectLanguages/ui/NoSelectedLanguages.tsx new file mode 100644 index 0000000..1db2d94 --- /dev/null +++ b/src/features/language/SelectLanguages/ui/NoSelectedLanguages.tsx @@ -0,0 +1,5 @@ +export const NoSelectedLanguages = () => ( + + No languages to learn are selected. Select some languages to learn + +) diff --git a/src/features/language/SelectLanguages/ui/index.ts b/src/features/language/SelectLanguages/ui/index.ts index a58f0a2..0905d31 100644 --- a/src/features/language/SelectLanguages/ui/index.ts +++ b/src/features/language/SelectLanguages/ui/index.ts @@ -1 +1,2 @@ export { SelectLanguages } from './SelectLanguages' +export { NoSelectedLanguages } from './NoSelectedLanguages' From 60c19255248271ec897b094b5a7892489902e0d2 Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 01:28:46 +0400 Subject: [PATCH 03/12] chore: add dictionary types --- src/entities/dictionary/model/types.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/entities/dictionary/model/types.ts diff --git a/src/entities/dictionary/model/types.ts b/src/entities/dictionary/model/types.ts new file mode 100644 index 0000000..f8a867a --- /dev/null +++ b/src/entities/dictionary/model/types.ts @@ -0,0 +1,15 @@ +interface IDictionaryCommonFields { + id: string + name: string + url: string +} + +export interface IDictionaryWithVariants extends IDictionaryCommonFields { + variants: { + label: string + value: string + }[] + activeVariant: string +} + +export type IDictionary = IDictionaryCommonFields | IDictionaryWithVariants From ddd5cb7e0293008e44fff85c06e0eab59283459d Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 01:29:51 +0400 Subject: [PATCH 04/12] chore: add select dictionary variant component --- .../ui/SelectDictionaryVariant.tsx | 36 +++++++++++++++++++ .../ui/styles.module.scss | 5 +++ 2 files changed, 41 insertions(+) create mode 100644 src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx create mode 100644 src/features/dictionary/SelectDictionaryVariant/ui/styles.module.scss diff --git a/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx new file mode 100644 index 0000000..ad533b2 --- /dev/null +++ b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx @@ -0,0 +1,36 @@ +import { DictionaryCard, IDictionaryWithVariants } from '@entities/dictionary' + +import { Button } from '@shared/ui/Button' + +import styles from './styles.module.scss' + +interface GroupProps { + dictionary: IDictionaryWithVariants +} + +export const SelectDictionaryVariant = ({ dictionary }: GroupProps) => { + return ( +
      + {dictionary.variants.map((variant) => { + const isActive = dictionary.activeVariant === variant.value + return ( + console.log('select variant')} + > + {isActive + ? `${variant.label} version is used` + : `Use ${variant.label} version`} + + } + /> + ) + })} +
    + ) +} diff --git a/src/features/dictionary/SelectDictionaryVariant/ui/styles.module.scss b/src/features/dictionary/SelectDictionaryVariant/ui/styles.module.scss new file mode 100644 index 0000000..51ece4e --- /dev/null +++ b/src/features/dictionary/SelectDictionaryVariant/ui/styles.module.scss @@ -0,0 +1,5 @@ +.variants { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-2); +} From a9b063e12af49432b11a55384f543e095e4eb716 Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 04:05:42 +0400 Subject: [PATCH 05/12] chore: add languages global store --- .../language/model/__tests__/store.test.ts | 79 +++++++++++++++++++ src/entities/language/model/index.ts | 1 + src/entities/language/model/store.ts | 43 ++++++++++ .../model/__tests__/store.test.ts | 78 ++++++------------ .../language/SelectLanguages/model/store.ts | 60 +++++--------- .../SelectLanguages/ui/SelectLanguages.tsx | 12 ++- 6 files changed, 176 insertions(+), 97 deletions(-) create mode 100644 src/entities/language/model/__tests__/store.test.ts create mode 100644 src/entities/language/model/store.ts diff --git a/src/entities/language/model/__tests__/store.test.ts b/src/entities/language/model/__tests__/store.test.ts new file mode 100644 index 0000000..db5179b --- /dev/null +++ b/src/entities/language/model/__tests__/store.test.ts @@ -0,0 +1,79 @@ +import { allTasks, cleanStores, keepMount } from 'nanostores' +import { afterEach, describe, expect, test, vi } from 'vitest' + +import { Result } from '@shared/libs/operationResult' +import { getErrorToastMock } from '@shared/ui/Toast/helpers/__mock__/getErrorToast' +import { addToastMock } from '@shared/ui/Toast/model/__mock__/store' + +import { waitFor } from '@tests/testUtils' + +import { ILanguage } from '..' +import { $languages, LanguagesStorage, select } from '../store' + +describe('selectedLanguageCodes store', () => { + const language: ILanguage = { label: 'English', value: 'en' } + const error = { + type: `ERROR`, + error: null, + } + + afterEach(async () => { + await chrome.storage.local.clear() + cleanStores($languages) + $languages.set([]) + }) + + describe('commmon', () => { + test('should set value from languages', async () => { + await LanguagesStorage.set([language]) + + keepMount($languages) + await allTasks() + + expect($languages.get()).toEqual([language]) + expect(getErrorToastMock).toBeCalledTimes(0) + }) + + test('should set empty array and show toast with error when SelectedLanguagesStorage returns error', async () => { + vi.spyOn(LanguagesStorage, 'get').mockResolvedValueOnce( + Result.Error(error), + ) + + keepMount($languages) + await allTasks() + + expect($languages.get()).toEqual([]) + expect(getErrorToastMock).toBeCalledWith(error) + }) + }) + + describe('commit', () => { + test('should set to selected languages store selected values and show opration success information', async () => { + $languages.set([language]) + + keepMount($languages) + await allTasks() + + waitFor(async () => { + select([]) + + const call = addToastMock.mock.calls[0] + expect(call[0].type).toBe('success') + expect(call[0].title).toBeDefined() + }) + }) + + test('should show error when can not update languages', async () => { + vi.spyOn(LanguagesStorage, 'set').mockResolvedValue(Result.Error(error)) + + keepMount($languages) + await allTasks() + + waitFor(async () => { + select([]) + + expect(getErrorToastMock).toBeCalledWith(error) + }) + }) + }) +}) diff --git a/src/entities/language/model/index.ts b/src/entities/language/model/index.ts index 013f6d4..2f77c1f 100644 --- a/src/entities/language/model/index.ts +++ b/src/entities/language/model/index.ts @@ -1,2 +1,3 @@ export type { TLanguageCode, ILanguage } from './types' export { LANGUAGES } from './languages' +export * as languageStore from './store' diff --git a/src/entities/language/model/store.ts b/src/entities/language/model/store.ts new file mode 100644 index 0000000..a8610ab --- /dev/null +++ b/src/entities/language/model/store.ts @@ -0,0 +1,43 @@ +import { atom, onMount, task } from 'nanostores' + +import { ILanguage, TLanguageCode } from '@entities/language' +import { Storage } from '@entities/storage' + +import { browser } from '@shared/browser' +import { addToast, getErrorToast } from '@shared/ui/Toast' + +import { LANGUAGES } from './languages' + +type Languages = ILanguage[] + +export const LanguagesStorage = new Storage('languages', LANGUAGES) + +export const $languages = atom(LANGUAGES) + +onMount($languages, () => { + task(async () => { + const getResult = await LanguagesStorage.get() + if (getResult.data) { + $languages.set(getResult.data) + } else { + addToast(getErrorToast(getResult.error)) + } + }) +}) + +export const select = async (languageCodes: TLanguageCode[]) => { + const filteredLanguages = LANGUAGES.filter((language) => + languageCodes.includes(language.value), + ) + + const setResult = await LanguagesStorage.set(filteredLanguages) + if (setResult.data) { + $languages.set(filteredLanguages) + addToast({ + type: 'success', + title: browser.i18n.getMessage('SELECTED_LANGUAGES_SAVED'), + }) + } else { + addToast(getErrorToast(setResult.error)) + } +} diff --git a/src/features/language/SelectLanguages/model/__tests__/store.test.ts b/src/features/language/SelectLanguages/model/__tests__/store.test.ts index 14f722f..b72a52c 100644 --- a/src/features/language/SelectLanguages/model/__tests__/store.test.ts +++ b/src/features/language/SelectLanguages/model/__tests__/store.test.ts @@ -1,70 +1,52 @@ import { allTasks, cleanStores, keepMount } from 'nanostores' -import { afterEach, describe, expect, test, vi } from 'vitest' +import { afterEach, describe, expect, test } from 'vitest' + +import { languageStore } from '@entities/language' -import { Result } from '@shared/libs/operationResult' import { getErrorToastMock } from '@shared/ui/Toast/helpers/__mock__/getErrorToast' import { addToastMock } from '@shared/ui/Toast/model/__mock__/store' import { waitFor } from '@tests/testUtils' import { - $selectedLanguages, - SelectedLanguagesStorage, + $languageCodes, checkIsSelected, commit, reset, toggle, } from '../store' -describe('selectedLanguages store', () => { - const error = { - type: `ERROR`, - error: null, - } - +describe('selectedLanguageCodes store', () => { afterEach(async () => { await chrome.storage.local.clear() - cleanStores($selectedLanguages) - $selectedLanguages.set([]) - }) - - test('should initialize with empty array', () => { - keepMount($selectedLanguages) - - expect($selectedLanguages.get()).toEqual([]) - expect(getErrorToastMock).toBeCalledTimes(0) + cleanStores($languageCodes) + $languageCodes.set([]) }) describe('commmon', () => { - test('should set value from SelectedLanguagesStorage', async () => { - await SelectedLanguagesStorage.set(['en']) + test('should initialize with empty array', () => { + keepMount($languageCodes) - keepMount($selectedLanguages) - await allTasks() - - expect($selectedLanguages.get()).toEqual(['en']) + expect($languageCodes.get()).toEqual([]) expect(getErrorToastMock).toBeCalledTimes(0) }) - test('should set empty array and show toast with error when SelectedLanguagesStorage returns error', async () => { - vi.spyOn(SelectedLanguagesStorage, 'get').mockResolvedValueOnce( - Result.Error(error), - ) + test('should set value from languages', async () => { + languageStore.$languages.set([{ label: 'English', value: 'en' }]) - keepMount($selectedLanguages) + keepMount($languageCodes) await allTasks() - expect($selectedLanguages.get()).toEqual([]) - expect(getErrorToastMock).toBeCalledWith(error) + expect($languageCodes.get()).toEqual(['en']) + expect(getErrorToastMock).toBeCalledTimes(0) }) }) describe('toggle', () => { test('should select language if not selected and reset', async () => { - await SelectedLanguagesStorage.set([]) + languageStore.$languages.set([]) - keepMount($selectedLanguages) - await allTasks() + keepMount($languageCodes) toggle('en') expect(checkIsSelected('en')).toBeTruthy() @@ -74,10 +56,9 @@ describe('selectedLanguages store', () => { }) test('should unselect language if selected and reset', async () => { - await SelectedLanguagesStorage.set(['en']) + languageStore.$languages.set([{ label: 'English', value: 'en' }]) - keepMount($selectedLanguages) - await allTasks() + keepMount($languageCodes) toggle('en') expect(checkIsSelected('en')).toBeFalsy() @@ -89,33 +70,18 @@ describe('selectedLanguages store', () => { describe('commit', () => { test('should set to selected languages store selected values and show opration success information', async () => { - $selectedLanguages.set(['en']) + $languageCodes.set(['en']) - keepMount($selectedLanguages) + keepMount($languageCodes) await allTasks() waitFor(async () => { - await commit() + commit() const call = addToastMock.mock.calls[0] expect(call[0].type).toBe('success') expect(call[0].title).toBeDefined() }) }) - - test('should show error when can not update languages', async () => { - vi.spyOn(SelectedLanguagesStorage, 'set').mockResolvedValue( - Result.Error(error), - ) - - keepMount($selectedLanguages) - await allTasks() - - waitFor(async () => { - await commit() - - expect(getErrorToastMock).toBeCalledWith(error) - }) - }) }) }) diff --git a/src/features/language/SelectLanguages/model/store.ts b/src/features/language/SelectLanguages/model/store.ts index 1ac3008..852c24e 100644 --- a/src/features/language/SelectLanguages/model/store.ts +++ b/src/features/language/SelectLanguages/model/store.ts @@ -1,56 +1,38 @@ -import { atom, onMount, task } from 'nanostores' +import { atom } from 'nanostores' -import { TLanguageCode } from '@entities/language' -import { Storage } from '@entities/storage' - -import { browser } from '@shared/browser' -import { addToast, getErrorToast } from '@shared/ui/Toast' - -export const SelectedLanguagesStorage = new Storage( - 'selected_languages', - [], -) +import { TLanguageCode, languageStore } from '@entities/language' let defaultValue: TLanguageCode[] = [] -export const $selectedLanguages = atom([]) - -onMount($selectedLanguages, () => { - task(async () => { - const getResult = await SelectedLanguagesStorage.get() - if (getResult.data) { - defaultValue = getResult.data - $selectedLanguages.set(getResult.data) - } else { - addToast(getErrorToast(getResult.error)) - } - }) +export const $languageCodes = atom([]) +export const $islanguageCodesDirty = atom(true) + +languageStore.$languages.listen((newValue) => { + if ($islanguageCodesDirty.get()) { + const languageCodes = newValue.map((language) => language.value) + defaultValue = languageCodes + $languageCodes.set(languageCodes) + } }) export const toggle = async (languageCode: TLanguageCode) => { - const isSelected = $selectedLanguages.get().includes(languageCode) + $islanguageCodesDirty.set(true) + const isSelected = $languageCodes.get().includes(languageCode) const newSelectedLanguages = isSelected - ? $selectedLanguages.get().filter((lang) => lang !== languageCode) - : [...$selectedLanguages.get(), languageCode] + ? $languageCodes.get().filter((lang) => lang !== languageCode) + : [...$languageCodes.get(), languageCode] - $selectedLanguages.set(newSelectedLanguages) + $languageCodes.set(newSelectedLanguages) } -export const checkIsSelected = (languageCode: TLanguageCode) => { - return $selectedLanguages.get().includes(languageCode) +export const checkIsSelected = (languageCode: TLanguageCode): boolean => { + return $languageCodes.get().includes(languageCode) } export const reset = () => { - $selectedLanguages.set(defaultValue) + $languageCodes.set(defaultValue) } -export const commit = async () => { - const setResult = await SelectedLanguagesStorage.set($selectedLanguages.get()) - - setResult.data - ? addToast({ - type: 'success', - title: browser.i18n.getMessage('SELECTED_LANGUAGES_SAVED'), - }) - : addToast(getErrorToast(setResult.error)) +export const commit = () => { + languageStore.select($languageCodes.get()) } diff --git a/src/features/language/SelectLanguages/ui/SelectLanguages.tsx b/src/features/language/SelectLanguages/ui/SelectLanguages.tsx index 58b7292..063f3cc 100644 --- a/src/features/language/SelectLanguages/ui/SelectLanguages.tsx +++ b/src/features/language/SelectLanguages/ui/SelectLanguages.tsx @@ -1,17 +1,25 @@ +import { useStore } from '@nanostores/preact' import { JSXInternal } from 'node_modules/preact/src/jsx' -import { ILanguage } from '@entities/language/model' +import { ILanguage } from '@entities/language' import { browser } from '@shared/browser' import { Button } from '@shared/ui/Button' -import { checkIsSelected, commit, reset, toggle } from '../model/store' +import { + $languageCodes, + checkIsSelected, + commit, + reset, + toggle, +} from '../model/store' interface Props { languages: ILanguage[] } export const SelectLanguages = ({ languages }: Props) => { + useStore($languageCodes) const onSubmit: JSXInternal.SubmitEventHandler = (e) => { e.preventDefault() commit() From bcec2f017e56fd99ae6c2d9b09c036df8cf7166e Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 04:27:08 +0400 Subject: [PATCH 06/12] chore: add dictionary store --- src/entities/dictionary/index.ts | 2 + src/entities/dictionary/model/index.ts | 2 + src/entities/dictionary/model/store.ts | 155 +++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 src/entities/dictionary/index.ts create mode 100644 src/entities/dictionary/model/index.ts create mode 100644 src/entities/dictionary/model/store.ts diff --git a/src/entities/dictionary/index.ts b/src/entities/dictionary/index.ts new file mode 100644 index 0000000..1ccc9c5 --- /dev/null +++ b/src/entities/dictionary/index.ts @@ -0,0 +1,2 @@ +export * from './ui' +export * from './model' diff --git a/src/entities/dictionary/model/index.ts b/src/entities/dictionary/model/index.ts new file mode 100644 index 0000000..465e519 --- /dev/null +++ b/src/entities/dictionary/model/index.ts @@ -0,0 +1,2 @@ +export type { IDictionary, IDictionaryWithVariants } from './types' +export * as dictionaryStore from './store' diff --git a/src/entities/dictionary/model/store.ts b/src/entities/dictionary/model/store.ts new file mode 100644 index 0000000..55bacc8 --- /dev/null +++ b/src/entities/dictionary/model/store.ts @@ -0,0 +1,155 @@ +import { atom, onMount, task } from 'nanostores' + +import { ILanguage, TLanguageCode } from '@entities/language' +import { Storage } from '@entities/storage' + +import { addToast, getErrorToast } from '@shared/ui/Toast' + +import { IDictionary } from './types' + +type Dictionaries = Record< + TLanguageCode, + ILanguage & { + dictionaries: Array + } +> +const defaultDictionaries: Dictionaries = { + en: { + label: 'English', + value: 'en', + dictionaries: [ + { + id: 'en_CambridgeDictionary', + name: 'Cambridge Dictionary', + url: 'https://dictionary.cambridge.org/', + variants: [ + { + label: 'American', + value: 'us', + }, + { + label: 'British', + value: 'uk', + }, + ], + activeVariant: 'uk', + }, + { + id: 'en_MerriamWebster', + name: 'Merriam-Webster', + url: 'https://www.merriam-webster.com/dictionary', + }, + { + id: 'en_Collins', + name: 'Collins', + url: 'https://www.collinsdictionary.com/dictionary/english', + variants: [ + { + label: 'American', + value: 'us', + }, + { + label: 'British', + value: 'uk', + }, + ], + activeVariant: 'uk', + }, + { + id: 'en_Wordreference', + name: 'Wordreference', + url: 'https://www.wordreference.com/definition', + variants: [ + { + label: 'American', + value: 'us', + }, + { + label: 'British', + value: 'uk', + }, + ], + activeVariant: 'uk', + }, + { + id: 'en_GoogleTranslate', + name: 'Google Translate', + url: 'https://translate.google.com/', + }, + ], + }, + jp: { + label: 'Japanese', + value: 'jp', + dictionaries: [ + { + id: 'jp_Jisho', + name: 'Jisho', + url: 'https://jisho.org/', + }, + ], + }, + pt: { + label: 'Portuguese', + value: 'pt', + dictionaries: [ + { + id: 'jp_Jisho', + name: 'Jisho', + url: 'https://jisho.org/', + }, + ], + }, + ko: { + label: 'Korean', + value: 'ko', + dictionaries: [ + { + id: 'jp_Jisho', + name: 'Jisho', + url: 'https://jisho.org/', + }, + ], + }, +} + +export const DictionariesStorage = new Storage( + 'dictionaries', + defaultDictionaries, +) + +export const $dictionaries = atom(defaultDictionaries) + +onMount($dictionaries, () => { + task(async () => { + const getResult = await DictionariesStorage.get() + if (getResult.data) { + $dictionaries.set(getResult.data) + } else { + addToast(getErrorToast(getResult.error)) + } + }) +}) + +export const selectVariant = async ( + languageCode: TLanguageCode, + dictionaryId: string, + variant: string, +) => { + const dictionaries = $dictionaries.get() + + const dictionary = dictionaries[languageCode].dictionaries.find( + (dictionary) => dictionary.id === dictionaryId, + ) + + if (dictionary && 'variants' in dictionary) { + dictionary.activeVariant = variant + } + + const setResult = await DictionariesStorage.set(dictionaries) + if (setResult.data) { + $dictionaries.set({ ...dictionaries }) + } else { + addToast(getErrorToast(setResult.error)) + } +} From 7f56790d1486f3061a47937541b68c54f39eee8d Mon Sep 17 00:00:00 2001 From: Alina Date: Sun, 24 Mar 2024 04:27:30 +0400 Subject: [PATCH 07/12] feat: add select dictionary variant feature --- src/app/popup/Popup.tsx | 2 + .../SelectDictionaryVariant/index.ts | 1 + .../ui/SelectDictionaryList.tsx | 72 +++++++++++++++++++ .../ui/SelectDictionaryVariant.tsx | 14 +++- .../SelectDictionaryVariant/ui/index.ts | 1 + .../ui/styles.module.scss | 6 ++ 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/features/dictionary/SelectDictionaryVariant/index.ts create mode 100644 src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryList.tsx create mode 100644 src/features/dictionary/SelectDictionaryVariant/ui/index.ts diff --git a/src/app/popup/Popup.tsx b/src/app/popup/Popup.tsx index a2a2381..7a24ad8 100644 --- a/src/app/popup/Popup.tsx +++ b/src/app/popup/Popup.tsx @@ -1,3 +1,4 @@ +import { SelectDictionaryList } from '@features/dictionary/SelectDictionaryVariant' import { SelectLanguages } from '@features/language/SelectLanguages' import { LANGUAGES } from '@entities/language' @@ -7,6 +8,7 @@ import { Toasts } from '@shared/ui/Toast' export const Popup = () => { return (
    +
    diff --git a/src/features/dictionary/SelectDictionaryVariant/index.ts b/src/features/dictionary/SelectDictionaryVariant/index.ts new file mode 100644 index 0000000..ed58495 --- /dev/null +++ b/src/features/dictionary/SelectDictionaryVariant/index.ts @@ -0,0 +1 @@ +export * from './ui' diff --git a/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryList.tsx b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryList.tsx new file mode 100644 index 0000000..d92ab4d --- /dev/null +++ b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryList.tsx @@ -0,0 +1,72 @@ +import { useStore } from '@nanostores/preact' + +import { NoSelectedLanguages } from '@features/language/SelectLanguages' + +import { DictionaryCard, dictionaryStore } from '@entities/dictionary' +import { languageStore } from '@entities/language' + +import { Tab, TabPanel, Tabs, TabsList, a11yProps } from '@shared/ui/Tabs' + +import { SelectDictionaryVariant } from './SelectDictionaryVariant' +import styles from './styles.module.scss' + +export const SelectDictionaryList = () => { + const dictionaries = useStore(dictionaryStore.$dictionaries) + const languages = useStore(languageStore.$languages) + + return ( + <> + {languages.length ? ( + <> + + + {languages.map((language) => ( + + {language.label} + + ))} + + {languages.map((language) => { + return ( + +
      + {dictionaries[language.value].dictionaries.map( + (dictionary) => { + if ('variants' in dictionary) { + return ( +
    • + +
    • + ) + } else { + return ( + + ) + } + }, + )} +
    +
    + ) + })} +
    + + ) : ( + + )} + + ) +} diff --git a/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx index ad533b2..8503060 100644 --- a/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx +++ b/src/features/dictionary/SelectDictionaryVariant/ui/SelectDictionaryVariant.tsx @@ -1,4 +1,8 @@ -import { DictionaryCard, IDictionaryWithVariants } from '@entities/dictionary' +import { + DictionaryCard, + IDictionaryWithVariants, + dictionaryStore, +} from '@entities/dictionary' import { Button } from '@shared/ui/Button' @@ -21,7 +25,13 @@ export const SelectDictionaryVariant = ({ dictionary }: GroupProps) => { actions={