ai-chatbot/components/canvas/nodes/image-node/image-node-empty-state.tsx

140 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { AlertCircle, ImagePlus, Loader2 } from "lucide-react";
import type React from "react";
import { GenerationDotPlaceholder } from "@/components/generation-dot-placeholder";
import type { RequestFailureDetails } from "@/lib/request-error";
interface ImageNodeEmptyStateProps {
detailProgressLabel?: string;
fileInputRef: React.Ref<HTMLInputElement>;
generationProgress?: number | null;
failure?: RequestFailureDetails;
requestId?: string;
onImageUpload: (event: React.ChangeEvent<HTMLInputElement>) => void;
onSelectFile: (event: React.MouseEvent<HTMLButtonElement>) => void;
status?: string;
viewportScale?: number;
}
export function ImageNodeDeferredLoadState() {
return (
<div className="flex h-full w-full items-center justify-center bg-slate-50 text-slate-400 text-xs dark:bg-zinc-900 dark:text-zinc-500">
<div className="flex flex-col items-center gap-2">
<Loader2 className="h-4 w-4 animate-spin" />
<span>图片即将进入视口时加载</span>
</div>
</div>
);
}
export function ImageNodeProcessingOverlay({
detailProgressLabel,
generationProgress,
viewportScale,
}: {
detailProgressLabel?: string;
generationProgress?: number | null;
viewportScale?: number;
}) {
return (
<div className="absolute inset-0 overflow-hidden rounded-[inherit] bg-white/96 backdrop-blur-[1px]">
<GenerationDotPlaceholder
className="h-full w-full rounded-none"
compact
phase="processing"
progress={generationProgress}
title={detailProgressLabel || "正在处理图片"}
viewportScale={viewportScale}
/>
</div>
);
}
export function ImageNodeEmptyState({
detailProgressLabel,
fileInputRef,
generationProgress,
failure,
requestId,
onImageUpload,
onSelectFile,
status,
viewportScale,
}: ImageNodeEmptyStateProps) {
if (status === "uploading") {
return (
<div className="flex h-full w-full select-none flex-col items-center justify-center bg-[#f7f9fc] px-6 text-center dark:bg-zinc-900">
<span className="mb-3 flex h-12 w-12 items-center justify-center rounded-[18px] border border-[#dde5f4] bg-white text-[#5b76fe] shadow-[0_0_0_1px_rgba(219,226,238,0.22)] dark:border-white/12 dark:bg-white/8">
<Loader2 className="h-5 w-5 animate-spin" />
</span>
<span className="select-none text-sm font-medium text-[#3f4b63] dark:text-zinc-200">
正在上传图片
</span>
<span className="mt-1 select-none text-xs text-[#7a8395] dark:text-zinc-500">
上传完成后会自动显示
</span>
</div>
);
}
if (status === "generating") {
return (
<GenerationDotPlaceholder
className="h-full w-full rounded-none"
compact
phase="processing"
progress={generationProgress}
title={detailProgressLabel || undefined}
viewportScale={viewportScale}
/>
);
}
if (status === "failed") {
const failedTitle = detailProgressLabel || "生成失败";
return (
<div role="alert" className="flex h-full w-full flex-col items-center justify-center overflow-auto bg-[#fff7f8] px-6 text-center dark:bg-red-950/40">
<span className="mb-3 flex h-12 w-12 items-center justify-center rounded-[18px] border border-[#f2d7dd] bg-white text-[#d24f63] shadow-[0_0_0_1px_rgba(242,215,221,0.22)]">
<AlertCircle className="h-5 w-5" />
</span>
<span className="select-none text-sm font-medium text-[#c84b5e]">
{failedTitle}
</span>
<span className="mt-1 text-xs text-[#b77480]">
{failure?.recommendation || (failedTitle.includes("上传") ? "请重新选择文件" : "请查看对话中的错误原因和处理建议")}
</span>
{requestId ? <span className="mt-2 select-text break-all text-xs text-[#b77480]">请求编号:{requestId}</span> : null}
</div>
);
}
return (
<div className="flex h-full w-full select-none flex-col items-center justify-center bg-[#f7f9fc] px-6 text-center dark:bg-zinc-900">
<span className="mb-3 flex h-12 w-12 items-center justify-center rounded-[18px] border border-[#dde5f4] bg-white text-[#5b76fe] shadow-[0_0_0_1px_rgba(219,226,238,0.22)]">
<ImagePlus className="h-5 w-5" />
</span>
<span className="select-none text-sm font-medium text-[#3f4b63]">
上传图片
</span>
<span className="mb-4 mt-1 select-none text-xs text-[#7a8395]">
添加参考图、角色图或关键帧素材
</span>
<input
accept="image/*"
className="hidden"
onChange={onImageUpload}
ref={fileInputRef}
type="file"
/>
<button
className="cursor-pointer rounded-[14px] border border-[#d7dff1] bg-white px-4 py-2 text-sm font-medium text-[#3954db] shadow-[0_0_0_1px_rgba(219,226,238,0.24)] transition-colors hover:bg-[#f4f7ff]"
onClick={onSelectFile}
type="button"
>
选择文件
</button>
</div>
);
}