This commit is contained in:
@@ -83,48 +83,22 @@
|
|||||||
"githubLogin": "GitHub Login"
|
"githubLogin": "GitHub Login"
|
||||||
},
|
},
|
||||||
"memorize": {
|
"memorize": {
|
||||||
"choose": {
|
|
||||||
"back": "Back",
|
|
||||||
"choose": "Choose"
|
|
||||||
},
|
|
||||||
"edit": {
|
|
||||||
"back": "Back",
|
|
||||||
"save": "Save Word Pairs",
|
|
||||||
"locale1": "Locale 1",
|
|
||||||
"locale2": "Locale 2"
|
|
||||||
},
|
|
||||||
"folder_selector": {
|
"folder_selector": {
|
||||||
"selectFolder": "Select a folder",
|
"selectFolder": "Select a folder",
|
||||||
"noFolders": "No folders found",
|
"noFolders": "No folders found",
|
||||||
"folderInfo": "{id}. {name} ({count})"
|
"folderInfo": "{id}. {name} ({count})"
|
||||||
},
|
},
|
||||||
"main": {
|
|
||||||
"title": "Memorize",
|
|
||||||
"locale1": "Your selected locale 1 is {locale}",
|
|
||||||
"locale2": "Your selected locale 2 is {locale}",
|
|
||||||
"total": "There are {total} word pairs in total",
|
|
||||||
"start": "Start",
|
|
||||||
"import": "Import",
|
|
||||||
"export": "Export",
|
|
||||||
"edit": "Edit"
|
|
||||||
},
|
|
||||||
"memorize": {
|
"memorize": {
|
||||||
"showAnswer": "Show Answer",
|
"showAnswer": "Show Answer",
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
"reverse": "Reverse",
|
"reverse": "Reverse",
|
||||||
"dictation": "Dictation",
|
"dictation": "Dictation",
|
||||||
"noTextPairs": "No text pairs available",
|
"noTextPairs": "No text pairs available",
|
||||||
"progress": "{current}/{total}"
|
"progress": "{current}/{total}",
|
||||||
|
"disorder": "Disorder"
|
||||||
},
|
},
|
||||||
"page": {
|
"page": {
|
||||||
"unauthorized": "You are not authorized to access this folder"
|
"unauthorized": "You are not authorized to access this folder"
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"show": "Show",
|
|
||||||
"reverse": "Reverse",
|
|
||||||
"dictation": "Dictation",
|
|
||||||
"back": "Back",
|
|
||||||
"next": "Next"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"navbar": {
|
"navbar": {
|
||||||
|
|||||||
@@ -87,44 +87,22 @@
|
|||||||
"back": "返回",
|
"back": "返回",
|
||||||
"choose": "选择"
|
"choose": "选择"
|
||||||
},
|
},
|
||||||
"edit": {
|
|
||||||
"back": "返回",
|
|
||||||
"save": "保存单词对",
|
|
||||||
"locale1": "区域1",
|
|
||||||
"locale2": "区域2"
|
|
||||||
},
|
|
||||||
"folder_selector": {
|
"folder_selector": {
|
||||||
"selectFolder": "选择文件夹",
|
"selectFolder": "选择文件夹",
|
||||||
"noFolders": "未找到文件夹",
|
"noFolders": "未找到文件夹",
|
||||||
"folderInfo": "{id}. {name} ({count})"
|
"folderInfo": "{id}. {name} ({count})"
|
||||||
},
|
},
|
||||||
"main": {
|
|
||||||
"title": "记忆",
|
|
||||||
"locale1": "您选择的区域一是{locale}",
|
|
||||||
"locale2": "您选择的区域二是{locale}",
|
|
||||||
"total": "总计有{total}个单词对",
|
|
||||||
"start": "开始",
|
|
||||||
"import": "导入",
|
|
||||||
"export": "导出",
|
|
||||||
"edit": "编辑"
|
|
||||||
},
|
|
||||||
"memorize": {
|
"memorize": {
|
||||||
"showAnswer": "显示答案",
|
"showAnswer": "显示答案",
|
||||||
"next": "下一个",
|
"next": "下一个",
|
||||||
"reverse": "反向",
|
"reverse": "反向",
|
||||||
"dictation": "听写",
|
"dictation": "听写",
|
||||||
"noTextPairs": "没有可用的文本对",
|
"noTextPairs": "没有可用的文本对",
|
||||||
"progress": "{current}/{total}"
|
"progress": "{current}/{total}",
|
||||||
|
"disorder": "乱序"
|
||||||
},
|
},
|
||||||
"page": {
|
"page": {
|
||||||
"unauthorized": "您无权访问该文件夹"
|
"unauthorized": "您无权访问该文件夹"
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"show": "显示",
|
|
||||||
"reverse": "反向",
|
|
||||||
"dictation": "听写",
|
|
||||||
"back": "返回",
|
|
||||||
"next": "下个"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"navbar": {
|
"navbar": {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { Center } from "@/components/Center";
|
import { Center } from "@/components/Center";
|
||||||
import { text_pair } from "../../../../generated/prisma/browser";
|
import { text_pair } from "../../../../generated/prisma/browser";
|
||||||
import Container from "@/components/cards/Container";
|
import Container from "@/components/cards/Container";
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import LightButton from "@/components/buttons/LightButton";
|
import LightButton from "@/components/buttons/LightButton";
|
||||||
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
|
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
|
||||||
import { getTTSAudioUrl } from "@/lib/browser/tts";
|
import { getTTSAudioUrl } from "@/lib/browser/tts";
|
||||||
@@ -18,18 +18,37 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
|
|||||||
const t = useTranslations("memorize.memorize");
|
const t = useTranslations("memorize.memorize");
|
||||||
const [reverse, setReverse] = useState(false);
|
const [reverse, setReverse] = useState(false);
|
||||||
const [dictation, setDictation] = useState(false);
|
const [dictation, setDictation] = useState(false);
|
||||||
|
const [disorder, setDisorder] = useState(false);
|
||||||
const [index, setIndex] = useState(0);
|
const [index, setIndex] = useState(0);
|
||||||
const [show, setShow] = useState<"question" | "answer">("question");
|
const [show, setShow] = useState<"question" | "answer">("question");
|
||||||
const { load, play } = useAudioPlayer();
|
const { load, play } = useAudioPlayer();
|
||||||
|
|
||||||
|
const [disorderedTextPairs, setDisorderedTextPairs] = useState<text_pair[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDisorderedTextPairs(textPairs.toSorted(() => Math.random() - 0.5));
|
||||||
|
}, [textPairs]);
|
||||||
|
|
||||||
|
const getTextPairs = () => {
|
||||||
|
if (disorder) {
|
||||||
|
return disorderedTextPairs;
|
||||||
|
}
|
||||||
|
return textPairs.toSorted((a, b) => a.id - b.id);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Center>
|
<Center>
|
||||||
<Container className="p-6 flex flex-col gap-8 h-96 justify-center items-center">
|
<Container className="p-6 flex flex-col gap-8 h-96 justify-center items-center">
|
||||||
{(textPairs.length > 0 && (
|
{(getTextPairs().length > 0 && (
|
||||||
<>
|
<>
|
||||||
<div className="h-36 flex flex-col gap-2 justify-start items-center font-serif text-3xl">
|
<div className="h-36 flex flex-col gap-2 justify-start items-center font-serif text-3xl">
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
{t("progress", { current: index + 1, total: textPairs.length })}
|
{t("progress", {
|
||||||
|
current: index + 1,
|
||||||
|
total: getTextPairs().length,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
{dictation ? (
|
{dictation ? (
|
||||||
show === "question" ? (
|
show === "question" ? (
|
||||||
@@ -38,26 +57,28 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
|
|||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{reverse
|
{reverse
|
||||||
? textPairs[index].text2
|
? getTextPairs()[index].text2
|
||||||
: textPairs[index].text1}
|
: getTextPairs()[index].text1}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{reverse
|
{reverse
|
||||||
? textPairs[index].text1
|
? getTextPairs()[index].text1
|
||||||
: textPairs[index].text2}
|
: getTextPairs()[index].text2}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{reverse ? textPairs[index].text2 : textPairs[index].text1}
|
{reverse
|
||||||
|
? getTextPairs()[index].text2
|
||||||
|
: getTextPairs()[index].text1}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{show === "answer"
|
{show === "answer"
|
||||||
? reverse
|
? reverse
|
||||||
? textPairs[index].text1
|
? getTextPairs()[index].text1
|
||||||
: textPairs[index].text2
|
: getTextPairs()[index].text2
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -68,15 +89,15 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
|
|||||||
className="w-32"
|
className="w-32"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (show === "answer") {
|
if (show === "answer") {
|
||||||
const newIndex = (index + 1) % textPairs.length;
|
const newIndex = (index + 1) % getTextPairs().length;
|
||||||
setIndex(newIndex);
|
setIndex(newIndex);
|
||||||
if (dictation)
|
if (dictation)
|
||||||
getTTSAudioUrl(
|
getTTSAudioUrl(
|
||||||
textPairs[newIndex][reverse ? "text2" : "text1"],
|
getTextPairs()[newIndex][reverse ? "text2" : "text1"],
|
||||||
VOICES.find(
|
VOICES.find(
|
||||||
(v) =>
|
(v) =>
|
||||||
v.locale ===
|
v.locale ===
|
||||||
textPairs[newIndex][
|
getTextPairs()[newIndex][
|
||||||
reverse ? "locale2" : "locale1"
|
reverse ? "locale2" : "locale1"
|
||||||
],
|
],
|
||||||
)!.short_name,
|
)!.short_name,
|
||||||
@@ -106,6 +127,14 @@ const Memorize: React.FC<MemorizeProps> = ({ textPairs }) => {
|
|||||||
>
|
>
|
||||||
{t("dictation")}
|
{t("dictation")}
|
||||||
</LightButton>
|
</LightButton>
|
||||||
|
<LightButton
|
||||||
|
onClick={() => {
|
||||||
|
setDisorder(!disorder);
|
||||||
|
}}
|
||||||
|
selected={disorder}
|
||||||
|
>
|
||||||
|
{t("disorder")}
|
||||||
|
</LightButton>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)) || <p>{t("noTextPairs")}</p>}
|
)) || <p>{t("noTextPairs")}</p>}
|
||||||
|
|||||||
Reference in New Issue
Block a user