...
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-12-11 21:36:45 +08:00
parent 65aacc1582
commit b69e168558
41 changed files with 763 additions and 189 deletions

View File

@@ -1,48 +1,37 @@
"use client";
import LightButton from "@/components/buttons/LightButton";
import { Letter, SupportedAlphabets } from "@/lib/interfaces";
import { useEffect, useState } from "react";
import MemoryCard from "./MemoryCard";
import { useState, useEffect } from "react";
import { useTranslations } from "next-intl";
import { Letter, SupportedAlphabets } from "@/lib/interfaces";
import Container from "@/components/ui/Container";
import LightButton from "@/components/ui/buttons/LightButton";
import AlphabetCard from "./AlphabetCard";
export default function Alphabet() {
const t = useTranslations("alphabet");
const [chosenAlphabet, setChosenAlphabet] =
useState<SupportedAlphabets | null>(null);
const [alphabetData, setAlphabetData] = useState<
Record<SupportedAlphabets, Letter[] | null>
>({
japanese: null,
english: null,
esperanto: null,
uyghur: null,
});
const [loadingState, setLoadingState] = useState<
"idle" | "loading" | "success" | "error"
>("idle");
const [chosenAlphabet, setChosenAlphabet] = useState<SupportedAlphabets | null>(null);
const [alphabetData, setAlphabetData] = useState<Letter[] | null>(null);
const [loadingState, setLoadingState] = useState<"idle" | "loading" | "success" | "error">("idle");
useEffect(() => {
if (chosenAlphabet && !alphabetData[chosenAlphabet]) {
setLoadingState("loading");
fetch("/alphabets/" + chosenAlphabet + ".json")
.then((res) => {
const loadAlphabetData = async () => {
if (chosenAlphabet && !alphabetData) {
try {
setLoadingState("loading");
const res = await fetch("/alphabets/" + chosenAlphabet + ".json");
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
})
.then((obj) => {
setAlphabetData((prev) => ({
...prev,
[chosenAlphabet]: obj as Letter[],
}));
const obj = await res.json();
setAlphabetData(obj as Letter[]);
setLoadingState("success");
})
.catch(() => {
} catch (error) {
setLoadingState("error");
});
}
}
}
};
loadAlphabetData();
}, [chosenAlphabet, alphabetData]);
useEffect(() => {
@@ -50,48 +39,106 @@ export default function Alphabet() {
const timer = setTimeout(() => {
setLoadingState("idle");
setChosenAlphabet(null);
setAlphabetData(null);
}, 2000);
return () => clearTimeout(timer);
}
}, [loadingState]);
if (!chosenAlphabet)
// 语言选择界面
if (!chosenAlphabet) {
return (
<>
<div className="border border-gray-200 m-4 mt-4 flex flex-col justify-center items-center p-4 rounded-2xl gap-2">
<span className="text-2xl md:text-3xl">{t("chooseCharacters")}</span>
<div className="flex gap-1 flex-wrap">
<LightButton onClick={() => setChosenAlphabet("japanese")}>
{t("japanese")}
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex flex-col items-center justify-center px-4">
<Container className="p-8 max-w-2xl w-full text-center">
<h1 className="text-4xl md:text-5xl font-bold text-gray-800 mb-4">
{t("chooseCharacters")}
</h1>
<p className="text-gray-600 mb-8 text-lg">
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<LightButton
onClick={() => setChosenAlphabet("japanese")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2"></span>
<span>{t("japanese")}</span>
</div>
</LightButton>
<LightButton onClick={() => setChosenAlphabet("english")}>
{t("english")}
<LightButton
onClick={() => setChosenAlphabet("english")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABC</span>
<span>{t("english")}</span>
</div>
</LightButton>
<LightButton onClick={() => setChosenAlphabet("uyghur")}>
{t("uyghur")}
<LightButton
onClick={() => setChosenAlphabet("uyghur")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ئۇيغۇر</span>
<span>{t("uyghur")}</span>
</div>
</LightButton>
<LightButton onClick={() => setChosenAlphabet("esperanto")}>
{t("esperanto")}
<LightButton
onClick={() => setChosenAlphabet("esperanto")}
className="p-6 text-lg font-medium hover:scale-105 transition-transform"
>
<div className="flex flex-col items-center">
<span className="text-2xl mb-2">ABCĜĤ</span>
<span>{t("esperanto")}</span>
</div>
</LightButton>
</div>
</div>
</>
</Container>
</div>
);
}
// 加载状态
if (loadingState === "loading") {
return t("loading");
}
if (loadingState === "error") {
return t("loadFailed");
}
if (loadingState === "success" && alphabetData[chosenAlphabet]) {
return (
<>
<MemoryCard
alphabet={alphabetData[chosenAlphabet]}
setChosenAlphabet={setChosenAlphabet}
></MemoryCard>
</>
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center">
<Container className="p-8 text-center">
<div className="text-2xl text-gray-600">{t("loading")}</div>
</Container>
</div>
);
}
// 错误状态
if (loadingState === "error") {
return (
<div className="min-h-[calc(100vh-64px)] bg-[#35786f] flex items-center justify-center">
<Container className="p-8 text-center">
<div className="text-2xl text-red-600">{t("loadFailed")}</div>
</Container>
</div>
);
}
// 字母卡片界面
if (loadingState === "success" && alphabetData) {
return (
<AlphabetCard
alphabet={alphabetData}
alphabetType={chosenAlphabet}
onBack={() => {
setChosenAlphabet(null);
setAlphabetData(null);
setLoadingState("idle");
}}
/>
);
}
return null;
}