diff --git a/frontend/src/features/book/api/loader.js b/frontend/src/features/book/api/loader.js index f7876848..99d87509 100644 --- a/frontend/src/features/book/api/loader.js +++ b/frontend/src/features/book/api/loader.js @@ -1,5 +1,5 @@ import { getBookQuery, getPageQuery } from "./query"; -import { definedLangInfoQuery } from "@language/api/language"; +import { userLanguageQuery } from "@language/api/query"; import { settingsQuery } from "@settings/api/settings"; import { softwareInfoQuery } from "@settings/api/settings"; @@ -12,7 +12,7 @@ function loader(queryClient) { const settingsData = await queryClient.ensureQueryData(settingsQuery); const languageData = await queryClient.ensureQueryData( - definedLangInfoQuery(bookData?.languageId) + userLanguageQuery(bookData?.languageId) ); const softwareInfoData = await queryClient.ensureQueryData(softwareInfoQuery); diff --git a/frontend/src/features/book/components/Book/Book.jsx b/frontend/src/features/book/components/Book/Book.jsx index 41041268..d263741f 100644 --- a/frontend/src/features/book/components/Book/Book.jsx +++ b/frontend/src/features/book/components/Book/Book.jsx @@ -3,7 +3,7 @@ import { useParams, useSearchParams } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { Box } from "@mantine/core"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; -import { definedLangInfoQuery } from "@language/api/language"; +import { userLanguageQuery } from "@language/api/query"; import { getTermQuery } from "@term/api/query"; import { paneResizeStorage } from "@actions/utils"; import PageSpinner from "@common/PageSpinner/PageSpinner"; @@ -50,7 +50,7 @@ function Book({ themeFormOpen, onThemeFormOpen, onDrawerOpen }) { : activeTerm.data); const { data: book } = useQuery(getBookQuery(id)); - const { data: language } = useQuery(definedLangInfoQuery(book.languageId)); + const { data: language } = useQuery(userLanguageQuery(book.languageId)); const { data: term } = useQuery(getTermQuery(key)); const [state, dispatch] = useBookState(); @@ -81,7 +81,7 @@ function Book({ themeFormOpen, onThemeFormOpen, onDrawerOpen }) { <> {!editMode && } - {editMode && } + {editMode && } ["definedLanguage", id], - - definedFormSettings: (id) => ["definedLanguageFormSettings", id], - predefinedFormSettings: (name) => ["predefinedLanguageFormSettings", name], - + userLanguages: ["userLanguages"], + predefinedLanguages: ["predefinedLanguages"], + userLanguage: (id) => ["definedLanguage", id], + predefinedLanguage: (name) => ["predefinedLanguage", name], parsers: ["languageParsers"], - samples: (langName) => ["sampleStories", langName], }; diff --git a/frontend/src/features/language/api/language.jsx b/frontend/src/features/language/api/language.jsx deleted file mode 100644 index 5d25df3d..00000000 --- a/frontend/src/features/language/api/language.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import { keys } from "./keys"; - -const definedLangInfoQuery = (id) => ({ - queryKey: keys.defined(id), - queryFn: async () => { - const response = await fetch(`http://localhost:5001/api/languages/${id}`); - return await response.json(); - }, - enabled: id != null && id !== "0", - refetchOnWindowFocus: false, -}); - -const defFormSettingsQuery = (id) => ({ - queryKey: keys.definedFormSettings(id), - queryFn: async () => { - const response = await fetch( - `http://localhost:5001/api/languages/${id}/settings` - ); - return await response.json(); - }, - enabled: id != null && id !== "0", -}); - -const predefFormSettingsQuery = (langName) => ({ - queryKey: keys.predefinedFormSettings(langName), - queryFn: async () => { - const response = await fetch( - `http://localhost:5001/api/languages/new/${langName}` - ); - return await response.json(); - }, - staleTime: Infinity, -}); - -const predefinedListQuery = { - queryKey: keys.predefined, - queryFn: async () => { - const response = await fetch( - `http://localhost:5001/api/languages/predefined` - ); - return await response.json(); - }, - staleTime: Infinity, -}; - -const definedListQuery = { - queryKey: keys.user, - queryFn: async () => { - const response = await fetch(`http://localhost:5001/api/languages/user`); - return await response.json(); - }, -}; - -const parsersQuery = { - queryKey: keys.parsers, - queryFn: async () => { - const response = await fetch("http://localhost:5001/api/languages/parsers"); - return await response.json(); - }, - staleTime: Infinity, -}; - -export { - definedListQuery, - predefinedListQuery, - parsersQuery, - definedLangInfoQuery, - defFormSettingsQuery, - predefFormSettingsQuery, -}; diff --git a/frontend/src/features/language/api/loader.js b/frontend/src/features/language/api/loader.js index dc516d28..3cff4f33 100644 --- a/frontend/src/features/language/api/loader.js +++ b/frontend/src/features/language/api/loader.js @@ -1,28 +1,24 @@ import { initialQuery } from "@settings/api/settings"; import { - definedListQuery, + userLanguagesQuery, parsersQuery, - predefFormSettingsQuery, - predefinedListQuery, -} from "./language"; + predefinedLanguagesQuery, +} from "./query"; function loader(queryClient) { return async () => { - const predefListData = - await queryClient.ensureQueryData(predefinedListQuery); - const defListData = await queryClient.ensureQueryData(definedListQuery); + const predefListData = await queryClient.ensureQueryData( + predefinedLanguagesQuery + ); + const defListData = await queryClient.ensureQueryData(userLanguagesQuery); const parsersData = await queryClient.ensureQueryData(parsersQuery); const initialData = await queryClient.ensureQueryData(initialQuery); - const predefinedSettingsData = await queryClient.ensureQueryData( - predefFormSettingsQuery(null) - ); return { predefListData, defListData, parsersData, initialData, - predefinedSettingsData, }; }; } diff --git a/frontend/src/features/language/api/query.js b/frontend/src/features/language/api/query.js new file mode 100644 index 00000000..f2665c50 --- /dev/null +++ b/frontend/src/features/language/api/query.js @@ -0,0 +1,46 @@ +import { + getLanguageParsers, + getPredefinedLanguage, + getPredefinedLanguages, + getUserLanguage, + getUserLanguages, +} from "./api"; +import { keys } from "./keys"; + +const userLanguageQuery = (id) => ({ + queryKey: keys.userLanguage(id), + queryFn: () => getUserLanguage(id), + enabled: id != null && id !== "0", + refetchOnWindowFocus: false, +}); + +const predefinedLanguageQuery = (langName) => ({ + queryKey: keys.predefinedLanguage(langName), + queryFn: () => getPredefinedLanguage(langName), + staleTime: Infinity, +}); + +const predefinedLanguagesQuery = { + queryKey: keys.predefinedLanguages, + queryFn: getPredefinedLanguages, + staleTime: Infinity, +}; + +const userLanguagesQuery = { + queryKey: keys.userLanguages, + queryFn: getUserLanguages, +}; + +const parsersQuery = { + queryKey: keys.parsers, + queryFn: getLanguageParsers, + staleTime: Infinity, +}; + +export { + userLanguagesQuery, + predefinedLanguagesQuery, + parsersQuery, + userLanguageQuery, + predefinedLanguageQuery, +}; diff --git a/frontend/src/features/language/components/DictTabs/DictTabs.jsx b/frontend/src/features/language/components/DictTabs/DictTabs.jsx index e0fde2ff..4a7d332b 100644 --- a/frontend/src/features/language/components/DictTabs/DictTabs.jsx +++ b/frontend/src/features/language/components/DictTabs/DictTabs.jsx @@ -28,9 +28,11 @@ function DictTabs({ onChange: onSetActiveTab, }); - const allDicts = language.dictionaries.term; - const visibleDicts = allDicts.slice(0, MAX_VISIBLE_DICT_TABS); - const dropdownDicts = allDicts.slice(MAX_VISIBLE_DICT_TABS); + const termDicts = language.dictionaries.filter( + (dict) => dict.for === "terms" + ); + const visibleDicts = termDicts.slice(0, MAX_VISIBLE_DICT_TABS); + const dropdownDicts = termDicts.slice(MAX_VISIBLE_DICT_TABS); // %E2%80%8B is the zero-width string. The term is reparsed // on the server, so this doesn't need to be sent. const encodedTermText = encodeURIComponent(termText).replaceAll( @@ -68,7 +70,7 @@ function DictTabs({ label={dict.label} openDelay={150} refProp="innerRef"> - {dict.isExternal ? ( + {dict.type === "popup" ? ( { return ( - !dict.isExternal && ( + dict.type === "embedded" && ( {languages - .toSorted((a, b) => a.id > b.id) + .toSorted((a, b) => b.id - a.id) .map((data) => ( { + if (!langId) { + form.reset(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [langId]); + return (
{openedFromLanguages && initial.haveLanguages && ( diff --git a/frontend/src/features/language/components/LanguageForm/LanguageSelect.jsx b/frontend/src/features/language/components/LanguageForm/LanguageSelect.jsx index b18fd957..54fec2ec 100644 --- a/frontend/src/features/language/components/LanguageForm/LanguageSelect.jsx +++ b/frontend/src/features/language/components/LanguageForm/LanguageSelect.jsx @@ -9,7 +9,7 @@ import { } from "@mantine/core"; import { IconLanguage } from "@tabler/icons-react"; -function LanguageSelect({ form, languages }) { +function LanguageSelect({ languages }) { const [params, setParams] = useSearchParams(); const { pathname } = useLocation(); @@ -30,7 +30,6 @@ function LanguageSelect({ form, languages }) { function handleClearField() { setSearch(""); setValue(null); - form.reset(); params.delete("name"); params.delete("langId"); setParams(params); diff --git a/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/DictionaryBar.jsx b/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/DictionaryBar.jsx index 75a3a1ad..2eaf9e44 100644 --- a/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/DictionaryBar.jsx +++ b/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/DictionaryBar.jsx @@ -8,12 +8,17 @@ import { Tooltip, } from "@mantine/core"; import { - IconExternalLink, IconGripVertical, IconSquareRoundedMinusFilled, } from "@tabler/icons-react"; +import TestDictionaryButton from "./components/TestDictionaryButton"; function DictionaryBar({ form, index, dndProvided }) { + const testUrl = form + .getValues() + .dictionaries[index]?.url.replace("###", "test") + .replace("[LUTE]", "test"); + return ( 2 ? false : true} + disabled={form.getValues().dictionaries.length <= 2} key={form.key(`dictionaries.${index}.active`)} {...form.getInputProps(`dictionaries.${index}.active`, { type: "checkbox", @@ -46,11 +51,7 @@ function DictionaryBar({ form, index, dndProvided }) { placeholder="Dictionary URL" rightSection={ form.getValues().dictionaries[index]?.url.length > 0 ? ( - - - - - + ) : null } key={form.key(`dictionaries.${index}.url`)} diff --git a/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/components/TestDictionaryButton.jsx b/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/components/TestDictionaryButton.jsx new file mode 100644 index 00000000..fe360438 --- /dev/null +++ b/frontend/src/features/language/components/LanguageForm/components/DictionaryBar/components/TestDictionaryButton.jsx @@ -0,0 +1,42 @@ +import { + ActionIcon, + Divider, + Popover, + Stack, + Text, + Tooltip, +} from "@mantine/core"; +import { IconExternalLink } from "@tabler/icons-react"; + +function TestDictionaryButton({ src }) { + return ( + + + + + + + + + + + + If you see the expected content, this dictionary can be embedded; if + not, change the type to "Pop-up". + + + + +