feat: show canvas action credit tooltips

This commit is contained in:
134 2026-06-14 14:30:19 +08:00
parent 898ed98f1a
commit 85930dc1a6

View File

@ -163,6 +163,7 @@ import {
type PublicThreeDModelAliasConfig,
} from "@/lib/model3d/model-alias-config";
import {
calculateEnhanceProPointsEstimate,
defaultPointsSystemConfig,
get3DTaskCreditCost,
get3DWorldCreditCost,
@ -357,8 +358,10 @@ function ImageActionCreditBadge({
return (
<span
className={cn(
"ml-auto inline-flex shrink-0 items-center gap-1 rounded-md bg-slate-900 px-1.5 py-0.5 text-[11px] font-semibold leading-none text-white shadow-sm dark:bg-white dark:text-slate-950",
compact && "ml-1 px-1 text-[10px]",
"inline-flex shrink-0 items-center gap-1 rounded-md bg-slate-900 px-1.5 py-0.5 text-[11px] font-semibold leading-none text-white shadow-sm dark:bg-white dark:text-slate-950",
compact
? "pointer-events-none absolute -top-8 left-1/2 z-20 -translate-x-1/2 opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100"
: "ml-auto",
className
)}
title={label}
@ -1895,6 +1898,25 @@ export function ImageNode({
const extendCostShortLabel = getImageToolCostShortLabel("extend");
const promptRegenerateCostShortLabel = getImageToolCostShortLabel("repaint");
const angleEditCostShortLabel = getImageToolCostShortLabel("angle-edit");
const enhanceCostShortLabel = formatImageNodeFeatureCostShortLabel({
cost: calculateEnhanceProPointsEstimate(pointsSystemConfig, {
width: Math.max(1, Math.round(node.size.width || 1)),
height: Math.max(1, Math.round(node.size.height || 1)),
upscalingActivated: true,
scaleFactor: 2,
}).cost,
isHighVip,
pointsEnabled:
pointsEnabled && pointsSystemConfig.enhanceProPricing.enabled === true,
});
const aiWashQuickCostShortLabel =
pointsEnabled && selectedAiWashQuickModel
? formatImageNodeFeatureCostShortLabel({
cost: selectedAiWashQuickModel.unitCost,
isHighVip,
pointsEnabled,
})
: null;
// 🆕 物品拾取相关状态
const isPickerMode = useCanvasStore((state) => state.isPickerMode);
@ -8533,6 +8555,7 @@ export function ImageNode({
item={imageEnhanceItem}
/>
{imageEnhanceItem.label}
<ImageActionCreditBadge label={enhanceCostShortLabel} />
</DropdownMenuItem>
) : null}
{imageNoteEnabled ? (
@ -9160,7 +9183,7 @@ export function ImageNode({
{isSelectedImageActionInline("enhance") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("enhance")}
title={imageEnhanceItem.label}
@ -9172,12 +9195,13 @@ export function ImageNode({
item={imageEnhanceItem}
/>
{imageEnhanceItem.label}
<ImageActionCreditBadge compact label={enhanceCostShortLabel} />
</Button>
) : null}
{isSelectedImageActionInline("removeBackground") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("rmbg")}
title={imageRemoveBackgroundItem.label}
@ -9199,7 +9223,7 @@ export function ImageNode({
{isSelectedImageActionInline("aiWashQuick") ? (
<Button
className={cn(
"h-10 rounded-xl px-3 font-medium text-[13px] transition",
"group relative h-10 rounded-xl px-3 font-medium text-[13px] transition",
aiWashQuickPanelOpen
? "bg-slate-950 text-white hover:bg-slate-900 hover:text-white dark:bg-white dark:text-slate-950 dark:hover:bg-slate-100"
: "text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
@ -9220,6 +9244,10 @@ export function ImageNode({
/>
)}
{aiWashQuickModeLabel}
<ImageActionCreditBadge
compact
label={aiWashQuickCostShortLabel}
/>
</Button>
) : null}
@ -9242,7 +9270,7 @@ export function ImageNode({
{isSelectedImageActionInline("boxCutout") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("box-cutout")}
title={imageBoxCutoutItem.label}
@ -9277,7 +9305,7 @@ export function ImageNode({
{isSelectedImageActionInline("removeWatermark") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("watermark")}
title={imageRemoveWatermarkItem.label}
@ -9315,7 +9343,7 @@ export function ImageNode({
{isSelectedImageActionInline("multiAngle") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("angle")}
title={imageMultiAngleItem.label}
@ -9336,7 +9364,7 @@ export function ImageNode({
{isSelectedImageActionInline("generate3dModel") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("generate-3d-model")}
title={imageGenerate3dModelItem.label}
@ -9357,7 +9385,7 @@ export function ImageNode({
{isSelectedImageActionInline("generate3dWorld") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("generate-3d-world")}
title={imageGenerate3dWorldItem.label}
@ -9395,7 +9423,7 @@ export function ImageNode({
{isSelectedImageActionInline("extend") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("extend")}
title={imageExtendItem.label}
@ -9464,7 +9492,7 @@ export function ImageNode({
{isSelectedImageActionInline("promptRegenerate") ? (
<Button
className="h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
className="group relative h-10 rounded-xl px-3 font-medium text-[13px] text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-100 dark:hover:bg-zinc-800"
disabled={isProcessing}
onClick={() => handleAction("prompt-regenerate")}
title={imagePromptRegenerateItem.label}
@ -10526,7 +10554,7 @@ export function ImageNode({
取消
</button>
<button
className="inline-flex h-[50px] items-center justify-center gap-2 rounded-[18px] bg-[#2d2f34] text-[17px] font-semibold text-white transition-colors hover:bg-[#23252a] disabled:cursor-not-allowed disabled:bg-[#cfd2d8] disabled:text-white/80"
className="group relative inline-flex h-[50px] items-center justify-center gap-2 rounded-[18px] bg-[#2d2f34] text-[17px] font-semibold text-white transition-colors hover:bg-[#23252a] disabled:cursor-not-allowed disabled:bg-[#cfd2d8] disabled:text-white/80"
disabled={isApplyingAngleEdit}
onClick={() => void handleApplyAngleEdit()}
type="button"