Fix liuyao UX: CSS coins, region auto-select, and clearer AI flow.

Replace missing coin images with CSS 3D coins, auto-select city on province change, expand Shandong cities, and improve AI interpretation prompts after six casts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-10 21:24:51 +08:00
parent a1667eac51
commit 96b659fbe5
6 changed files with 123 additions and 64 deletions
+39 -35
View File
@@ -1,6 +1,5 @@
import React, { useEffect, useState } from "react";
import clsx from "clsx";
import Image from "next/image";
const rotationDuration = 3800;
const bezier = "cubic-bezier(0.645,0.045,0.355,1)";
@@ -8,21 +7,21 @@ const bezier = "cubic-bezier(0.645,0.045,0.355,1)";
function Coin(props: {
frontList: boolean[];
rotation: boolean;
onTransitionEnd: any;
onTransitionEnd: () => void;
}) {
const [lastFront, setLastFront] = useState(props.frontList);
useEffect(function () {
useEffect(() => {
if (!props.rotation) {
return;
}
let id = setTimeout(function () {
const id = setTimeout(() => {
setLastFront(props.frontList);
props.onTransitionEnd();
}, rotationDuration);
return () => clearTimeout(id);
});
}, [props.rotation, props.frontList, props.onTransitionEnd]);
return (
<div className="flex w-full max-w-md justify-around rounded-md border bg-secondary p-4 shadow dark:border-0 dark:shadow-none sm:p-6">
@@ -38,50 +37,55 @@ function Coin(props: {
);
}
function CoinFace({ side }: { side: "front" | "back" }) {
const isFront = side === "front";
return (
<div
className={clsx(
"absolute inset-0 flex items-center justify-center rounded-full border-[3px] shadow-inner",
isFront
? "border-amber-500 bg-gradient-to-br from-amber-200 to-amber-400 text-amber-950"
: "border-stone-500 bg-gradient-to-br from-stone-300 to-stone-500 text-stone-800",
)}
style={{
backfaceVisibility: "hidden",
transform: isFront ? undefined : "rotateY(180deg)",
}}
>
<span className="select-none text-lg font-bold sm:text-xl">
{isFront ? "正" : "反"}
</span>
</div>
);
}
function CoinItem(props: {
front: boolean;
lastFront: boolean;
rotation: boolean;
onTransitionEnd?: any;
}) {
let animate = "";
if (props.rotation) {
// animate-[coin-front-front_3.8s_cubic-bezier(0.645,0.045,0.355,1)]
// animate-[coin-front-back_3.8s_cubic-bezier(0.645,0.045,0.355,1)]
// animate-[coin-back-front_3.8s_cubic-bezier(0.645,0.045,0.355,1)]
// animate-[coin-back-back_3.8s_cubic-bezier(0.645,0.045,0.355,1)]
animate = `animate-[coin-${getFront(props.lastFront)}-${getFront(
props.front,
)}_${rotationDuration / 1000}s_${bezier}]`;
}
return (
<div
style={{
transform: `rotateY(${props.front ? 0 : 180}deg)`,
transformStyle: "preserve-3d",
transformOrigin: "50% 50% -0.5px",
}}
className={clsx("h-16 w-16 sm:h-20 sm:w-20", animate)}
className="h-16 w-16 sm:h-20 sm:w-20"
style={{ perspective: "800px" }}
>
<Image
width={0}
height={0}
sizes="100vw"
draggable={false}
className="absolute w-full"
src="/img/head.webp"
alt="coin"
/>
<Image
width={0}
height={0}
sizes="100vw"
draggable={false}
className="absolute h-full w-full"
style={{ transform: "translateZ(-1px)" }}
src="/img/tail.webp"
alt="coin"
/>
<div
style={{
transform: `rotateY(${props.front ? 0 : 180}deg)`,
transformStyle: "preserve-3d",
}}
className={clsx("relative h-full w-full", animate)}
>
<CoinFace side="front" />
<CoinFace side="back" />
</div>
</div>
);
}