Fix learn 404, coin animation, full regions, and AI key errors.
Use numeric /learn/{num} routes, register Tailwind coin animations with方孔铜钱 UI, expand to 34 provinces, and surface missing OPENAI_API_KEY clearly.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { bool } from "aimless.js";
|
||||
import Coin from "@/components/coin";
|
||||
import Hexagram from "@/components/hexagram";
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
YAO_LABELS,
|
||||
} from "@/lib/calc/hexagram";
|
||||
|
||||
const AUTO_DELAY = 600;
|
||||
const AUTO_DELAY = 800;
|
||||
|
||||
interface HexagramInputProps {
|
||||
mode: "online" | "offline";
|
||||
@@ -30,43 +30,30 @@ export default function HexagramInput({
|
||||
}: HexagramInputProps) {
|
||||
const [frontList, setFrontList] = useState([true, true, true]);
|
||||
const [rotation, setRotation] = useState(false);
|
||||
const [hexagramList, setHexagramList] = useState<
|
||||
GuaResult["list"]
|
||||
>([]);
|
||||
const [count, setCount] = useState(0);
|
||||
const [hexagramList, setHexagramList] = useState<GuaResult["list"]>([]);
|
||||
const [offlineCounts, setOfflineCounts] = useState<(number | null)[]>(
|
||||
Array(6).fill(null),
|
||||
);
|
||||
|
||||
const complete = hexagramList.length === 6;
|
||||
|
||||
useEffect(() => {
|
||||
setHexagramList([]);
|
||||
setCount(0);
|
||||
setOfflineCounts(Array(6).fill(null));
|
||||
setRotation(false);
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
mode !== "online" ||
|
||||
!enabled ||
|
||||
rotation ||
|
||||
hexagramList.length >= 6 ||
|
||||
count >= 6
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const timer = setTimeout(startOnlineCast, AUTO_DELAY);
|
||||
return () => clearTimeout(timer);
|
||||
}, [mode, enabled, rotation, count, hexagramList.length]);
|
||||
const finishList = useCallback(
|
||||
(list: GuaResult["list"]) => {
|
||||
const result = computeGuaResult(list);
|
||||
if (result) {
|
||||
onResult({ list, result });
|
||||
}
|
||||
},
|
||||
[onResult],
|
||||
);
|
||||
|
||||
function finishList(list: GuaResult["list"]) {
|
||||
const result = computeGuaResult(list);
|
||||
if (result) {
|
||||
onResult({ list, result });
|
||||
}
|
||||
}
|
||||
|
||||
function onTransitionEnd() {
|
||||
const onTransitionEnd = useCallback(() => {
|
||||
setRotation(false);
|
||||
const frontCount = frontList.reduce(
|
||||
(acc, val) => (val ? acc + 1 : acc),
|
||||
@@ -86,16 +73,23 @@ export default function HexagramInput({
|
||||
}
|
||||
return newList;
|
||||
});
|
||||
}
|
||||
}, [frontList, finishList]);
|
||||
|
||||
function startOnlineCast() {
|
||||
const startOnlineCast = useCallback(() => {
|
||||
if (rotation || !enabled || hexagramList.length >= 6) {
|
||||
return;
|
||||
}
|
||||
setFrontList([bool(), bool(), bool()]);
|
||||
setRotation(true);
|
||||
setCount((c) => c + 1);
|
||||
}
|
||||
}, [rotation, enabled, hexagramList.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode !== "online" || !enabled || rotation || complete) {
|
||||
return;
|
||||
}
|
||||
const timer = setTimeout(startOnlineCast, AUTO_DELAY);
|
||||
return () => clearTimeout(timer);
|
||||
}, [mode, enabled, rotation, complete, hexagramList.length, startOnlineCast]);
|
||||
|
||||
function handleOfflineSelect(index: number, frontCount: number) {
|
||||
const next = [...offlineCounts];
|
||||
@@ -114,13 +108,11 @@ export default function HexagramInput({
|
||||
|
||||
function handleReset() {
|
||||
setHexagramList([]);
|
||||
setCount(0);
|
||||
setOfflineCounts(Array(6).fill(null));
|
||||
setRotation(false);
|
||||
onClear();
|
||||
}
|
||||
|
||||
const complete = hexagramList.length === 6;
|
||||
const offlineReady = offlineCounts.every((v) => v !== null);
|
||||
|
||||
if (!enabled) {
|
||||
@@ -133,7 +125,7 @@ export default function HexagramInput({
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center gap-4">
|
||||
{mode === "online" && !complete && (
|
||||
{mode === "online" && (
|
||||
<>
|
||||
<Coin
|
||||
onTransitionEnd={onTransitionEnd}
|
||||
@@ -143,9 +135,12 @@ export default function HexagramInput({
|
||||
<span className="text-lg font-medium">
|
||||
🎲 第{" "}
|
||||
<span className="font-mono text-xl font-bold text-orange-500">
|
||||
{count === 0 ? "-/-" : `${count}/6`}
|
||||
{complete ? "6/6" : `${hexagramList.length + (rotation ? 1 : 0)}/6`}
|
||||
</span>{" "}
|
||||
次卜筮
|
||||
{rotation && (
|
||||
<span className="ml-2 text-sm text-muted-foreground">铜钱旋转中…</span>
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -71,10 +71,10 @@ export default function RegionSelect({
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
{cityOptional && provinceCode && (
|
||||
{cityOptional && provinceCode && location && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
城市可不选,默认使用省份经度;已选:
|
||||
{location ? `${location.name}(${location.longitude}°)` : "—"}
|
||||
城市可选;未选城市时使用省份经度。当前:
|
||||
{location.name}({location.longitude}°)
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user