refactor(*): 代码质量 - 优化前后端实现并完善协议与画布验证
This commit is contained in:
@@ -1,45 +1,25 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { LoaderCircle } from "lucide-react";
|
||||
|
||||
import { formatDuration } from "@/lib/image-utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const pendingMessages = ["正在创建图片", "马上就好了", "再等等", "正在整理细节"];
|
||||
|
||||
export function ImageGenerationPending({ className, label, compact = false }: { className?: string; label?: string; compact?: boolean }) {
|
||||
const [tick, setTick] = useState(0);
|
||||
type PendingImageProps = { className?: string; label?: string; compact?: boolean };
|
||||
|
||||
export function ImageGenerationPending({ className, label = "正在生成图片", compact = false }: PendingImageProps) {
|
||||
const [startedAt] = useState(() => Date.now());
|
||||
const [elapsed, setElapsed] = useState(0);
|
||||
useEffect(() => {
|
||||
const timer = window.setInterval(() => setTick((value) => value + 1), 1000);
|
||||
return () => window.clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
const index = Math.floor(tick / 2) % pendingMessages.length;
|
||||
const progress = Math.min(98, 10 + (1 - Math.exp(-tick / 28)) * 88);
|
||||
|
||||
const update = () => setElapsed(Math.max(0, Date.now() - startedAt));
|
||||
const clock = window.setInterval(update, 1000);
|
||||
const onVisible = () => { if (!document.hidden) update(); };
|
||||
document.addEventListener("visibilitychange", onVisible);
|
||||
return () => { window.clearInterval(clock); document.removeEventListener("visibilitychange", onVisible); };
|
||||
}, [startedAt]);
|
||||
return (
|
||||
<div className={cn("relative overflow-hidden bg-stone-100 dark:bg-white/10", compact ? "min-h-24" : "aspect-[4/3]", className)}>
|
||||
<div
|
||||
className="absolute inset-0 opacity-60"
|
||||
style={{
|
||||
backgroundImage: "radial-gradient(circle, rgba(120,113,108,0.35) 1.4px, transparent 1.6px)",
|
||||
backgroundSize: "16px 16px",
|
||||
maskImage: "radial-gradient(ellipse at 38% 68%, black 0%, black 28%, transparent 60%)",
|
||||
}}
|
||||
/>
|
||||
<div className="absolute left-4 top-4 flex items-center gap-2 text-[var(--fs-body-lg)] font-medium text-stone-500 dark:text-stone-300">
|
||||
<LoaderCircle className="size-4 animate-spin" />
|
||||
<span>{label || pendingMessages[index]}</span>
|
||||
</div>
|
||||
<div className="absolute bottom-4 left-4 right-4">
|
||||
<div className="mb-2 flex items-center justify-between text-xs text-stone-500 dark:text-stone-400">
|
||||
<span>{formatDuration(tick * 1000)}</span>
|
||||
<span>{Math.floor(progress)}%</span>
|
||||
</div>
|
||||
<div className="h-1.5 rounded-full bg-stone-300/70 dark:bg-white/12">
|
||||
<div className="h-full rounded-full bg-stone-900 dark:bg-stone-100" style={{ width: `${progress}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
<div aria-busy="true" className={cn("flex flex-col items-center justify-center gap-3 rounded-lg bg-surface-active p-4 text-muted-foreground", compact ? "min-h-24" : "aspect-[4/3]", className)}>
|
||||
<LoaderCircle aria-hidden="true" className="size-5 animate-spin motion-reduce:animate-none" />
|
||||
<span role="status" className="text-sm font-medium">{label}</span>
|
||||
<time className="text-xs tabular-nums" dateTime={`PT${Math.floor(elapsed / 1000)}S`}>已等待 {formatDuration(elapsed)}</time>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user