fix: refine detail stitch preview and passthrough flow
This commit is contained in:
parent
ac58f28612
commit
81cd4d1754
@ -246,6 +246,20 @@ export function AgentDetailReferenceStitchDialog({
|
||||
),
|
||||
[cards]
|
||||
);
|
||||
const validCardLoadKey = useMemo(
|
||||
() =>
|
||||
validCards
|
||||
.map((card) => `${card.id}::${String(card.imageUrl || "").trim()}`)
|
||||
.join("|"),
|
||||
[validCards]
|
||||
);
|
||||
const setupCardsRef = useRef(validCards);
|
||||
const setupCardsKeyRef = useRef(validCardLoadKey);
|
||||
if (setupCardsKeyRef.current !== validCardLoadKey) {
|
||||
setupCardsKeyRef.current = validCardLoadKey;
|
||||
setupCardsRef.current = validCards;
|
||||
}
|
||||
const setupCards = setupCardsRef.current;
|
||||
|
||||
const normalizedCutLines = useMemo(
|
||||
() =>
|
||||
@ -301,7 +315,7 @@ export function AgentDetailReferenceStitchDialog({
|
||||
return;
|
||||
}
|
||||
|
||||
if (validCards.length === 0) {
|
||||
if (setupCards.length === 0) {
|
||||
setSnapshot(null);
|
||||
setCutLines([]);
|
||||
setErrorText(`当前没有可拼合的${sourceLabel}`);
|
||||
@ -317,11 +331,12 @@ export function AgentDetailReferenceStitchDialog({
|
||||
setIsLoading(true);
|
||||
setErrorText(null);
|
||||
setWarningText(null);
|
||||
setLoadingProgressText(`正在加载参考图 0/${setupCards.length}`);
|
||||
|
||||
const failedCards: string[] = [];
|
||||
let processedCount = 0;
|
||||
|
||||
for (const [index, card] of validCards.entries()) {
|
||||
setLoadingProgressText(`正在加载参考图 ${index + 1}/${validCards.length}`);
|
||||
for (const [index, card] of setupCards.entries()) {
|
||||
try {
|
||||
const loaded = await loadImage(card.imageUrl);
|
||||
loadedImages.push({
|
||||
@ -340,6 +355,11 @@ export function AgentDetailReferenceStitchDialog({
|
||||
imageUrl: card.imageUrl,
|
||||
error,
|
||||
});
|
||||
} finally {
|
||||
processedCount += 1;
|
||||
if (!cancelled) {
|
||||
setLoadingProgressText(`正在加载参考图 ${processedCount}/${setupCards.length}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,7 +401,7 @@ export function AgentDetailReferenceStitchDialog({
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [open, sourceLabel, validCards]);
|
||||
}, [open, setupCards, sourceLabel]);
|
||||
|
||||
useEffect(() => {
|
||||
const validIndexes = new Set(sliceSegments.map((segment) => segment.index));
|
||||
@ -640,6 +660,15 @@ export function AgentDetailReferenceStitchDialog({
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent
|
||||
className="h-[92vh] max-w-[1440px] overflow-hidden border-white/10 bg-[#060809] p-0 text-white"
|
||||
onEscapeKeyDown={(event) => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
onInteractOutside={(event) => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
onPointerDownOutside={(event) => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
overlayClassName="bg-black/85 backdrop-blur-sm"
|
||||
>
|
||||
<DialogHeader className="border-b border-white/10 px-6 py-5">
|
||||
@ -731,70 +760,72 @@ export function AgentDetailReferenceStitchDialog({
|
||||
{warningText}
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
ref={previewContainerRef}
|
||||
className="relative overflow-hidden rounded-[24px] border border-white/10 bg-white"
|
||||
onPointerMove={handlePreviewPointerMove}
|
||||
onPointerLeave={handlePreviewPointerLeave}
|
||||
onClick={handlePreviewClick}
|
||||
>
|
||||
<canvas
|
||||
ref={previewCanvasRef}
|
||||
className="block h-auto w-full select-none"
|
||||
/>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
ref={previewContainerRef}
|
||||
className="relative w-full max-w-[650px] overflow-hidden rounded-[24px] border border-white/10 bg-white shadow-[0_18px_48px_rgba(0,0,0,0.22)]"
|
||||
onPointerMove={handlePreviewPointerMove}
|
||||
onPointerLeave={handlePreviewPointerLeave}
|
||||
onClick={handlePreviewClick}
|
||||
>
|
||||
<canvas
|
||||
ref={previewCanvasRef}
|
||||
className="block h-auto w-full select-none"
|
||||
/>
|
||||
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
{isAddingCutLine && previewCutLineY !== null ? (
|
||||
<div
|
||||
className="absolute inset-x-0"
|
||||
style={{ top: `${(previewCutLineY / snapshot.height) * 100}%` }}
|
||||
>
|
||||
<div className="absolute inset-x-0 flex -translate-y-1/2 items-center justify-center">
|
||||
<div className="relative w-full">
|
||||
<div className="h-[2px] w-full border-t border-dashed border-emerald-400 bg-transparent" />
|
||||
<div className="absolute left-3 top-1/2 -translate-y-1/2 rounded-full border border-emerald-300/35 bg-black/72 px-2 py-1 text-[11px] text-emerald-100">
|
||||
点击落线
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{normalizedCutLines.map((lineY, index) => {
|
||||
const topPercent = (lineY / snapshot.height) * 100;
|
||||
return (
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
{isAddingCutLine && previewCutLineY !== null ? (
|
||||
<div
|
||||
key={`cut-line-${index}-${lineY}`}
|
||||
className="absolute inset-x-0"
|
||||
style={{ top: `${topPercent}%` }}
|
||||
style={{ top: `${(previewCutLineY / snapshot.height) * 100}%` }}
|
||||
>
|
||||
<div
|
||||
onPointerDown={handleLinePointerDown(index)}
|
||||
className={cn(
|
||||
"pointer-events-auto absolute inset-x-0 flex -translate-y-1/2 cursor-row-resize items-center justify-center",
|
||||
draggingLineIndex === index && "z-20"
|
||||
)}
|
||||
style={{ touchAction: "none" }}
|
||||
>
|
||||
<div className="absolute inset-x-0 flex -translate-y-1/2 items-center justify-center">
|
||||
<div className="relative w-full">
|
||||
<div className="h-[2px] w-full bg-emerald-400 shadow-[0_0_16px_rgba(52,211,153,0.42)]" />
|
||||
<div className="h-[2px] w-full border-t border-dashed border-emerald-400 bg-transparent" />
|
||||
<div className="absolute left-3 top-1/2 -translate-y-1/2 rounded-full border border-emerald-300/35 bg-black/72 px-2 py-1 text-[11px] text-emerald-100">
|
||||
切线 {index + 1}
|
||||
点击落线
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleRemoveCutLine(index);
|
||||
}}
|
||||
className="absolute right-3 top-1/2 pointer-events-auto -translate-y-1/2 rounded-full border border-white/12 bg-black/72 px-2 py-1 text-[11px] text-white/78 transition-colors hover:border-white/20 hover:text-white"
|
||||
>
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
) : null}
|
||||
{normalizedCutLines.map((lineY, index) => {
|
||||
const topPercent = (lineY / snapshot.height) * 100;
|
||||
return (
|
||||
<div
|
||||
key={`cut-line-${index}-${lineY}`}
|
||||
className="absolute inset-x-0"
|
||||
style={{ top: `${topPercent}%` }}
|
||||
>
|
||||
<div
|
||||
onPointerDown={handleLinePointerDown(index)}
|
||||
className={cn(
|
||||
"pointer-events-auto absolute inset-x-0 flex -translate-y-1/2 cursor-row-resize items-center justify-center",
|
||||
draggingLineIndex === index && "z-20"
|
||||
)}
|
||||
style={{ touchAction: "none" }}
|
||||
>
|
||||
<div className="relative w-full">
|
||||
<div className="h-[2px] w-full bg-emerald-400 shadow-[0_0_16px_rgba(52,211,153,0.42)]" />
|
||||
<div className="absolute left-3 top-1/2 -translate-y-1/2 rounded-full border border-emerald-300/35 bg-black/72 px-2 py-1 text-[11px] text-emerald-100">
|
||||
切线 {index + 1}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleRemoveCutLine(index);
|
||||
}}
|
||||
className="absolute right-3 top-1/2 pointer-events-auto -translate-y-1/2 rounded-full border border-white/12 bg-black/72 px-2 py-1 text-[11px] text-white/78 transition-colors hover:border-white/20 hover:text-white"
|
||||
>
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -810,7 +841,7 @@ export function AgentDetailReferenceStitchDialog({
|
||||
<div className="border-b border-white/10 px-5 py-4">
|
||||
<div className="text-sm font-semibold text-white">切割结果预估</div>
|
||||
<div className="mt-1 text-xs text-white/42">
|
||||
应用切割后,下方每一段都会回到详情替换参考图区;标记为“直接应用”的切片会跳过继续生成,未标记的切片再逐屏生成。
|
||||
应用切割后,下方每一段都会回到详情替换参考图区;标记为“不处理直出”的切片会跳过继续生成,未标记的切片再逐屏生成。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -835,7 +866,7 @@ export function AgentDetailReferenceStitchDialog({
|
||||
<div className="mt-3 flex items-center justify-between gap-2">
|
||||
<div className="text-[11px] text-white/45">
|
||||
{passthroughSegmentIndexSet.has(segment.index)
|
||||
? "当前切片会直接进入结果区,不继续生成。"
|
||||
? "当前切片不会参与生图,应用后会直接进入结果区。"
|
||||
: "当前切片会继续参与详情替换生成。"}
|
||||
</div>
|
||||
<button
|
||||
@ -855,8 +886,8 @@ export function AgentDetailReferenceStitchDialog({
|
||||
)}
|
||||
>
|
||||
{passthroughSegmentIndexSet.has(segment.index)
|
||||
? "取消直出"
|
||||
: "标记直接应用"}
|
||||
? "取消不处理"
|
||||
: "标记不处理"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -779,6 +779,9 @@ type ReplacementCardStatus =
|
||||
| "fallback"
|
||||
| "missing";
|
||||
|
||||
const MANUAL_PASSTHROUGH_RESULT_TEXT =
|
||||
"已按人工标记沿用参考图,直接应用当前切片,不参与继续生成。";
|
||||
|
||||
function inferReplacementCardStatusFromText(text: string | null | undefined): ReplacementCardStatus | null {
|
||||
const normalized = normalizeAssistantText(String(text || ""))
|
||||
.replace(/\s+/g, " ")
|
||||
@ -825,7 +828,7 @@ function getReplacementCardStatusMeta(status: ReplacementCardStatus) {
|
||||
switch (status) {
|
||||
case "passthrough":
|
||||
return {
|
||||
label: "沿用参考图",
|
||||
label: "不处理直出",
|
||||
className: "border-cyan-400/30 bg-cyan-500/[0.10] text-cyan-200",
|
||||
};
|
||||
case "fallback":
|
||||
@ -942,35 +945,53 @@ function AnimatedGenerationPlaceholderCard(params: {
|
||||
badge: string;
|
||||
badgeClassName?: string;
|
||||
showSpinner?: boolean;
|
||||
animated?: boolean;
|
||||
}) {
|
||||
const isAnimated = Boolean(params.animated);
|
||||
return (
|
||||
<div className="relative h-full w-full overflow-hidden bg-[linear-gradient(180deg,#060809_0%,#101417_100%)]">
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[-42%] origin-center"
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 5.2, repeat: Infinity, ease: "linear" }}
|
||||
>
|
||||
<div className="h-full w-full bg-[conic-gradient(from_0deg,rgba(16,185,129,0)_0deg,rgba(16,185,129,0.96)_42deg,rgba(34,211,238,0.86)_120deg,rgba(251,191,36,0.72)_198deg,rgba(168,85,247,0.88)_272deg,rgba(16,185,129,0)_360deg)] opacity-95" />
|
||||
</motion.div>
|
||||
<div className="absolute inset-[1.5px] rounded-[20px] bg-[linear-gradient(180deg,#080a0c_0%,#12171a_100%)]" />
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[1.5px] rounded-[20px] bg-[radial-gradient(circle_at_top,rgba(16,185,129,0.16),transparent_58%)]"
|
||||
animate={{ opacity: [0.42, 0.72, 0.42] }}
|
||||
transition={{ duration: 2.3, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[1.5px] rounded-[20px] opacity-70"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(118deg, transparent 8%, rgba(255,255,255,0.08) 36%, transparent 62%)",
|
||||
backgroundSize: "220% 100%",
|
||||
}}
|
||||
animate={{ backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"] }}
|
||||
transition={{ duration: 3.6, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"relative h-full w-full overflow-hidden rounded-[20px]",
|
||||
isAnimated
|
||||
? "bg-[linear-gradient(180deg,#060809_0%,#101417_100%)]"
|
||||
: "bg-[linear-gradient(180deg,#090c0e_0%,#12171a_100%)]"
|
||||
)}
|
||||
>
|
||||
{isAnimated ? (
|
||||
<>
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[-42%] origin-center"
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 5.2, repeat: Infinity, ease: "linear" }}
|
||||
>
|
||||
<div className="h-full w-full bg-[conic-gradient(from_0deg,rgba(16,185,129,0)_0deg,rgba(16,185,129,0.96)_42deg,rgba(34,211,238,0.86)_120deg,rgba(251,191,36,0.72)_198deg,rgba(168,85,247,0.88)_272deg,rgba(16,185,129,0)_360deg)] opacity-95" />
|
||||
</motion.div>
|
||||
<div className="absolute inset-[1.5px] rounded-[20px] bg-[linear-gradient(180deg,#080a0c_0%,#12171a_100%)]" />
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[1.5px] rounded-[20px] bg-[radial-gradient(circle_at_top,rgba(16,185,129,0.16),transparent_58%)]"
|
||||
animate={{ opacity: [0.42, 0.72, 0.42] }}
|
||||
transition={{ duration: 2.3, repeat: Infinity, ease: "easeInOut" }}
|
||||
/>
|
||||
<motion.div
|
||||
aria-hidden
|
||||
className="absolute inset-[1.5px] rounded-[20px] opacity-70"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(118deg, transparent 8%, rgba(255,255,255,0.08) 36%, transparent 62%)",
|
||||
backgroundSize: "220% 100%",
|
||||
}}
|
||||
animate={{ backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"] }}
|
||||
transition={{ duration: 3.6, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.06),transparent_58%)]" />
|
||||
<div className="absolute inset-x-0 bottom-0 h-20 bg-[linear-gradient(180deg,rgba(255,255,255,0)_0%,rgba(255,255,255,0.03)_100%)]" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="relative z-10 flex h-full flex-col items-center justify-center gap-3 px-5 text-center">
|
||||
<div className="flex items-center gap-2">
|
||||
@ -2408,20 +2429,34 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
() =>
|
||||
detailReplacementReferenceCards.map((card, index) => {
|
||||
const resultMeta = latestReplacementResults[index];
|
||||
const localPassthroughResultUrl =
|
||||
!resultMeta?.url && card.passthrough && card.imageUrl
|
||||
? card.imageUrl
|
||||
: null;
|
||||
const resultUrl =
|
||||
resultMeta?.url &&
|
||||
!normalizedDeletedResultCollections.detail_replacement.includes(resultMeta.url)
|
||||
? resultMeta.url
|
||||
: null;
|
||||
: localPassthroughResultUrl &&
|
||||
!normalizedDeletedResultCollections.detail_replacement.includes(
|
||||
localPassthroughResultUrl
|
||||
)
|
||||
? localPassthroughResultUrl
|
||||
: null;
|
||||
const resultText = resultMeta?.url
|
||||
? resultMeta?.text || ""
|
||||
: localPassthroughResultUrl
|
||||
? MANUAL_PASSTHROUGH_RESULT_TEXT
|
||||
: "";
|
||||
return {
|
||||
...card,
|
||||
index,
|
||||
resultUrl,
|
||||
resultText: resultUrl ? resultMeta?.text || "" : "",
|
||||
resultText,
|
||||
status: getReplacementCardStatus({
|
||||
index,
|
||||
resultUrl,
|
||||
resultText: resultUrl ? resultMeta?.text || "" : "",
|
||||
resultText,
|
||||
generatedCount: latestReplacementResults.length,
|
||||
isGenerating: isDetailResultModeGenerating,
|
||||
}),
|
||||
@ -2438,20 +2473,34 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
() =>
|
||||
skuReplacementReferenceCards.map((card, index) => {
|
||||
const resultMeta = latestReplacementResults[index];
|
||||
const localPassthroughResultUrl =
|
||||
!resultMeta?.url && card.passthrough && card.imageUrl
|
||||
? card.imageUrl
|
||||
: null;
|
||||
const resultUrl =
|
||||
resultMeta?.url &&
|
||||
!normalizedDeletedResultCollections.sku_replacement.includes(resultMeta.url)
|
||||
? resultMeta.url
|
||||
: null;
|
||||
: localPassthroughResultUrl &&
|
||||
!normalizedDeletedResultCollections.sku_replacement.includes(
|
||||
localPassthroughResultUrl
|
||||
)
|
||||
? localPassthroughResultUrl
|
||||
: null;
|
||||
const resultText = resultMeta?.url
|
||||
? resultMeta?.text || ""
|
||||
: localPassthroughResultUrl
|
||||
? MANUAL_PASSTHROUGH_RESULT_TEXT
|
||||
: "";
|
||||
return {
|
||||
...card,
|
||||
index,
|
||||
resultUrl,
|
||||
resultText: resultUrl ? resultMeta?.text || "" : "",
|
||||
resultText,
|
||||
status: getReplacementCardStatus({
|
||||
index,
|
||||
resultUrl,
|
||||
resultText: resultUrl ? resultMeta?.text || "" : "",
|
||||
resultText,
|
||||
generatedCount: latestReplacementResults.length,
|
||||
isGenerating: isSkuResultModeGenerating,
|
||||
}),
|
||||
@ -5639,7 +5688,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
</div>
|
||||
{card.passthrough ? (
|
||||
<div className="absolute right-3 top-12 rounded-full border border-cyan-300/35 bg-cyan-500/[0.14] px-2.5 py-1 text-[11px] text-cyan-100">
|
||||
直出结果
|
||||
不处理直出
|
||||
</div>
|
||||
) : null}
|
||||
{isActive ? (
|
||||
@ -5692,14 +5741,17 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
(() => {
|
||||
const isActive = activeDetailReferenceCardId === card.id;
|
||||
const statusMeta = getReplacementCardStatusMeta(card.status);
|
||||
const hasResult = Boolean(card.resultUrl);
|
||||
return (
|
||||
<div
|
||||
key={`${card.id}-result`}
|
||||
className={cn(
|
||||
"w-full cursor-pointer overflow-hidden rounded-[22px] border bg-black/20 transition-colors",
|
||||
isActive
|
||||
hasResult && isActive
|
||||
? "border-emerald-400/40 shadow-[0_0_0_1px_rgba(52,211,153,0.15)]"
|
||||
: "border-white/10"
|
||||
: isActive
|
||||
? "border-white/18 bg-white/[0.03] shadow-[0_0_0_1px_rgba(255,255,255,0.04)]"
|
||||
: "border-white/10"
|
||||
)}
|
||||
>
|
||||
{card.resultUrl ? (
|
||||
@ -5764,6 +5816,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<AnimatedGenerationPlaceholderCard
|
||||
badge={statusMeta.label}
|
||||
badgeClassName={statusMeta.className}
|
||||
animated={card.status === "generating"}
|
||||
showSpinner={card.status === "generating"}
|
||||
title={`结果图 ${card.index + 1}`}
|
||||
description={`将按“输入图组 + 第 ${card.index + 1} 张${detailReferenceSourceLabel}参考图”生成`}
|
||||
@ -6172,14 +6225,17 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
{skuResultCards.length > 0 ? (
|
||||
skuResultCards.map((card) => {
|
||||
const statusMeta = getReplacementCardStatusMeta(card.status);
|
||||
const hasResult = Boolean(card.resultUrl);
|
||||
return (
|
||||
<div
|
||||
key={`${card.id}-result`}
|
||||
className={cn(
|
||||
"w-full cursor-pointer overflow-hidden rounded-[22px] border bg-black/20 transition-colors",
|
||||
activeSkuReferenceCardId === card.id
|
||||
hasResult && activeSkuReferenceCardId === card.id
|
||||
? "border-emerald-400/40 shadow-[0_0_0_1px_rgba(52,211,153,0.15)]"
|
||||
: "border-white/10"
|
||||
: activeSkuReferenceCardId === card.id
|
||||
? "border-white/18 bg-white/[0.03] shadow-[0_0_0_1px_rgba(255,255,255,0.04)]"
|
||||
: "border-white/10"
|
||||
)}
|
||||
>
|
||||
{card.resultUrl ? (
|
||||
@ -6239,6 +6295,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<AnimatedGenerationPlaceholderCard
|
||||
badge={statusMeta.label}
|
||||
badgeClassName={statusMeta.className}
|
||||
animated={card.status === "generating"}
|
||||
showSpinner={card.status === "generating"}
|
||||
title={`结果图 ${card.index + 1}`}
|
||||
description={`将按“输入图 + 第 ${card.index + 1} 张${skuReferenceSourceLabel}参考图”生成`}
|
||||
@ -6314,9 +6371,11 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
className={cn(
|
||||
"overflow-hidden rounded-[22px] border transition-all",
|
||||
card.url ? "cursor-pointer" : "cursor-default",
|
||||
isActive
|
||||
card.url && isActive
|
||||
? "border-emerald-400/55 bg-emerald-500/[0.08] ring-1 ring-emerald-400/35"
|
||||
: "border-white/10 bg-black/20 hover:border-white/18"
|
||||
: !card.url && isActive
|
||||
? "border-white/18 bg-white/[0.03] shadow-[0_0_0_1px_rgba(255,255,255,0.04)]"
|
||||
: "border-white/10 bg-black/20 hover:border-white/18"
|
||||
)}
|
||||
>
|
||||
<div className="relative aspect-[4/5] overflow-hidden bg-[linear-gradient(180deg,#090b0c_0%,#111417_100%)]">
|
||||
@ -6432,6 +6491,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
? "border-white/12 bg-white/[0.05] text-white/62"
|
||||
: "border-white/10 bg-white/[0.04] text-white/58"
|
||||
}
|
||||
animated={card.status === "generating"}
|
||||
showSpinner={card.status === "generating"}
|
||||
title={`${getResultModeLabel(activeResultModeType)} 结果图 ${card.index + 1}`}
|
||||
description={
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user