improve workflow timeline and resize controls
This commit is contained in:
parent
399abb1ed3
commit
b088d65a66
@ -156,6 +156,14 @@ function getWorkflowStepOptionLevels(params: {
|
||||
return levels;
|
||||
}
|
||||
|
||||
function getWorkflowOptionDepthLabel(depth: number) {
|
||||
return depth === 1 ? "主卡片" : `${depth}级子卡片`;
|
||||
}
|
||||
|
||||
function getWorkflowOptionDepthShortLabel(depth: number) {
|
||||
return depth === 1 ? "主" : `${depth}级`;
|
||||
}
|
||||
|
||||
function StepOptionCard({
|
||||
option,
|
||||
step,
|
||||
@ -695,7 +703,10 @@ export function AgentWorkflowPanelDarkV2({
|
||||
selectionValue: selections[step.key],
|
||||
});
|
||||
const active = step.key === activeEmbeddedStepEntry.step.key;
|
||||
const stepSummary = stepSelectionSummaryMap[step.key] || "";
|
||||
const stepSelectedPath = getAgentWorkflowSelectedOptionPath({
|
||||
step,
|
||||
selectionValue: selections[step.key],
|
||||
});
|
||||
const stepOptionLevels = getWorkflowStepOptionLevels({
|
||||
step,
|
||||
selectionValue: selections[step.key],
|
||||
@ -707,9 +718,9 @@ export function AgentWorkflowPanelDarkV2({
|
||||
const activeStepChildLabel =
|
||||
active && stepOptionLevels.length > 1
|
||||
? `${
|
||||
activeEmbeddedOptionLevel?.depth === 1
|
||||
? "主卡片"
|
||||
: `${activeEmbeddedOptionLevel?.depth || 1}级子卡片`
|
||||
getWorkflowOptionDepthLabel(
|
||||
activeEmbeddedOptionLevel?.depth || 1
|
||||
)
|
||||
}`
|
||||
: deepestSelectedLevel > 1
|
||||
? `已到 ${deepestSelectedLevel} 级`
|
||||
@ -717,68 +728,102 @@ export function AgentWorkflowPanelDarkV2({
|
||||
|
||||
return (
|
||||
<Fragment key={step.key}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setPendingAutoAdvanceStepKey(null);
|
||||
setAutoAdvanceNotice(null);
|
||||
setActiveEmbeddedStepKey(step.key);
|
||||
}}
|
||||
className="group relative flex min-w-0 flex-col items-start pr-2 text-left transition-transform duration-200 hover:-translate-y-[1px]"
|
||||
>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<span
|
||||
className={cn(
|
||||
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full border text-[11px] font-semibold transition-colors",
|
||||
active
|
||||
? "border-emerald-300 bg-emerald-300 text-black shadow-[0_0_18px_rgba(52,211,153,0.28)]"
|
||||
: completed
|
||||
? "border-white/30 bg-white text-black"
|
||||
: "border-white/12 bg-white/[0.04] text-white/62 group-hover:border-white/24 group-hover:text-white/82"
|
||||
)}
|
||||
>
|
||||
{stepIndex + 1}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"truncate text-[13px] font-semibold transition-colors",
|
||||
active
|
||||
? "text-white"
|
||||
: completed
|
||||
? "text-white/82"
|
||||
: "text-white/52 group-hover:text-white/76"
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
{active ? (
|
||||
<span className="rounded-full border border-emerald-300/30 bg-emerald-400/10 px-2 py-0.5 text-[10px] font-medium text-emerald-200">
|
||||
当前步骤
|
||||
<div className="group relative flex min-w-0 flex-col items-start pr-2 text-left">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setPendingAutoAdvanceStepKey(null);
|
||||
setAutoAdvanceNotice(null);
|
||||
setActiveEmbeddedStepKey(step.key);
|
||||
setActiveEmbeddedOptionDepth(1);
|
||||
}}
|
||||
className="flex w-full flex-col items-start text-left transition-transform duration-200 hover:-translate-y-[1px]"
|
||||
>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<span
|
||||
className={cn(
|
||||
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full border text-[11px] font-semibold transition-colors",
|
||||
active
|
||||
? "border-emerald-300 bg-emerald-300 text-black shadow-[0_0_18px_rgba(52,211,153,0.28)]"
|
||||
: completed
|
||||
? "border-white/30 bg-white text-black"
|
||||
: "border-white/12 bg-white/[0.04] text-white/62 group-hover:border-white/24 group-hover:text-white/82"
|
||||
)}
|
||||
>
|
||||
{stepIndex + 1}
|
||||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"truncate text-[13px] font-semibold transition-colors",
|
||||
active
|
||||
? "text-white"
|
||||
: completed
|
||||
? "text-white/82"
|
||||
: "text-white/52 group-hover:text-white/76"
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
{active ? (
|
||||
<span className="rounded-full border border-emerald-300/30 bg-emerald-400/10 px-2 py-0.5 text-[10px] font-medium text-emerald-200">
|
||||
当前步骤
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
{activeStepChildLabel ? (
|
||||
<span
|
||||
className={cn(
|
||||
"mt-1.5 pl-10 text-[10px] leading-4",
|
||||
active ? "text-emerald-100/78" : "text-white/28"
|
||||
)}
|
||||
>
|
||||
{activeStepChildLabel}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
"mt-1.5 pl-10 text-[10px] leading-4",
|
||||
active
|
||||
? "text-emerald-100/78"
|
||||
: completed
|
||||
? "text-white/50"
|
||||
: "text-white/32"
|
||||
)}
|
||||
>
|
||||
{stepSummary || "待选择"}
|
||||
</span>
|
||||
{activeStepChildLabel ? (
|
||||
<span
|
||||
className={cn(
|
||||
"mt-1 pl-10 text-[10px] leading-4",
|
||||
active ? "text-emerald-200/72" : "text-white/28"
|
||||
)}
|
||||
>
|
||||
{activeStepChildLabel}
|
||||
</button>
|
||||
{stepSelectedPath.length > 0 ? (
|
||||
<div className="mt-2 flex flex-wrap gap-1.5 pl-10">
|
||||
{stepSelectedPath.map((option, optionIndex) => {
|
||||
const optionDepth = optionIndex + 1;
|
||||
const optionLevelActive =
|
||||
active &&
|
||||
(activeEmbeddedOptionLevel?.depth || 1) === optionDepth;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={`${step.key}-${option.key}-${optionDepth}`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setPendingAutoAdvanceStepKey(null);
|
||||
setAutoAdvanceNotice(null);
|
||||
setActiveEmbeddedStepKey(step.key);
|
||||
setActiveEmbeddedOptionDepth(optionDepth);
|
||||
}}
|
||||
className={cn(
|
||||
"inline-flex max-w-full items-center gap-1 rounded-full border px-2 py-1 text-[10px] leading-none transition-colors",
|
||||
optionLevelActive
|
||||
? "border-emerald-300/35 bg-emerald-400/12 text-emerald-100"
|
||||
: active || completed
|
||||
? "border-white/14 bg-white/[0.06] text-white/72 hover:border-white/22 hover:bg-white/[0.09] hover:text-white"
|
||||
: "border-white/10 bg-white/[0.03] text-white/48 hover:border-white/18 hover:text-white/72"
|
||||
)}
|
||||
title={`返回${getWorkflowOptionDepthLabel(optionDepth)}:${option.buttonName}`}
|
||||
>
|
||||
<span className="text-[9px] opacity-70">
|
||||
{getWorkflowOptionDepthShortLabel(optionDepth)}
|
||||
</span>
|
||||
<span className="max-w-[9rem] truncate">
|
||||
{option.buttonName}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<span className="mt-1.5 pl-10 text-[10px] leading-4 text-white/32">
|
||||
待选择
|
||||
</span>
|
||||
) : null}
|
||||
)}
|
||||
{stepIndex < flattenedResolvedSteps.length - 1 ? (
|
||||
<div
|
||||
className={cn(
|
||||
@ -789,7 +834,7 @@ export function AgentWorkflowPanelDarkV2({
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
@ -350,6 +350,10 @@ export function ImageAnnotator({
|
||||
{ label: "4:5", value: "4:5", ratio: 4 / 5 },
|
||||
{ label: "21:9", value: "21:9", ratio: 21 / 9 },
|
||||
];
|
||||
const resizeQuickPresets = [
|
||||
{ label: "主图 1440×1440", width: 1440, height: 1440, aspectRatioValue: "1:1" },
|
||||
{ label: "主图 1440×1920", width: 1440, height: 1920, aspectRatioValue: "3:4" },
|
||||
] as const;
|
||||
|
||||
// 根据比例和宽度计算高度
|
||||
const calculateHeightFromWidth = (width: number, ratio: number | null) => {
|
||||
@ -396,6 +400,14 @@ export function ImageAnnotator({
|
||||
}
|
||||
};
|
||||
|
||||
const handleResizeQuickPresetSelect = (
|
||||
preset: (typeof resizeQuickPresets)[number]
|
||||
) => {
|
||||
setResizeCanvasWidth(preset.width);
|
||||
setResizeCanvasHeight(preset.height);
|
||||
setSelectedAspectRatio(preset.aspectRatioValue);
|
||||
};
|
||||
|
||||
// 确保在客户端渲染
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
@ -1019,6 +1031,14 @@ export function ImageAnnotator({
|
||||
setResizeImageScale(newScale);
|
||||
};
|
||||
|
||||
const handleResizeScaleSliderChange = (value: number[]) => {
|
||||
const nextScale = value[0];
|
||||
if (!isResizeMode || typeof nextScale !== "number" || Number.isNaN(nextScale)) {
|
||||
return;
|
||||
}
|
||||
setResizeImageScale(Math.max(0.1, Math.min(5, nextScale)));
|
||||
};
|
||||
|
||||
// 尺寸调整:渲染预览
|
||||
useEffect(() => {
|
||||
if (!isResizeMode || !resizeCanvasRef.current || !image || !resizeContainerRef.current) return;
|
||||
@ -1754,6 +1774,44 @@ export function ImageAnnotator({
|
||||
/>
|
||||
</div>
|
||||
<div className="h-7 w-px shrink-0 bg-border/60" />
|
||||
<div className="flex items-center gap-1 rounded-[22px] bg-muted/35 px-1 py-1">
|
||||
{resizeQuickPresets.map((preset) => {
|
||||
const isActive =
|
||||
resizeCanvasWidth === preset.width && resizeCanvasHeight === preset.height;
|
||||
return (
|
||||
<Button
|
||||
key={`${preset.width}x${preset.height}`}
|
||||
variant={isActive ? "secondary" : "ghost"}
|
||||
size="sm"
|
||||
onClick={() => handleResizeQuickPresetSelect(preset)}
|
||||
className={cn(
|
||||
"h-8 rounded-[18px] px-3 text-xs font-medium whitespace-nowrap",
|
||||
isActive && "shadow-sm"
|
||||
)}
|
||||
>
|
||||
{preset.label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="h-7 w-px shrink-0 bg-border/60" />
|
||||
<div className="flex min-w-[220px] items-center gap-3 rounded-[22px] bg-muted/35 px-3 py-2">
|
||||
<span className="shrink-0 text-xs font-medium text-muted-foreground">
|
||||
缩放
|
||||
</span>
|
||||
<Slider
|
||||
value={[resizeImageScale]}
|
||||
onValueChange={handleResizeScaleSliderChange}
|
||||
min={0.1}
|
||||
max={5}
|
||||
step={0.01}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="min-w-[48px] shrink-0 text-right text-xs font-medium text-foreground">
|
||||
{(resizeImageScale * 100).toFixed(0)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-7 w-px shrink-0 bg-border/60" />
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user