mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 11:01:35 +00:00
UX: Improve video generation validation feedback (#965)
**UX: Improve video generation validation feedback** - Enable "Generate" button interactions to provide actionable error toasts instead of silent disabling. - Add inline "Starting frame required" warning with icon when a reference image is missing. - Update tooltip component to support conditional disabling for better UX control.
This commit is contained in:
1 parent
41f720ee08
commit
62b67ce2c4
2 files changed
+42
-23
No files matched your search
@@ -17,6 +17,7 @@ import {
|
||||
faSpinnerThird,
|
||||
faWaveformLines,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import {faCircleInfo} from "@fortawesome/pro-regular-svg-icons";
|
||||
import {
|
||||
faRectangle,
|
||||
faSquare,
|
||||
@@ -249,12 +250,13 @@ export const PromptBoxVideo = ({
|
||||
|
||||
if (!selectedModel) {
|
||||
console.warn("Cannot generate video: no model selected");
|
||||
toast.error("Please select a model to generate video");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedModel?.requiresImage && referenceImages.length === 0) {
|
||||
console.warn("Cannot generate video: no reference image provided");
|
||||
toast.error("Please choose a starting frame image to generate video");
|
||||
toast.error("Please add a starting frame image to generate video");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -393,7 +395,7 @@ export const PromptBoxVideo = ({
|
||||
<img
|
||||
src={image.url}
|
||||
alt="Reference preview"
|
||||
className="w-full h-full object-contain"
|
||||
className="h-full w-full object-contain"
|
||||
/>,
|
||||
);
|
||||
setIsModalOpen(true);
|
||||
@@ -517,26 +519,37 @@ export const PromptBoxVideo = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
className="flex items-center border-none bg-primary px-3 text-sm text-white disabled:cursor-not-allowed disabled:opacity-50"
|
||||
icon={!isEnqueueing ? faSparkles : undefined}
|
||||
onClick={handleEnqueue}
|
||||
disabled={
|
||||
isEnqueueing ||
|
||||
!prompt.trim() ||
|
||||
modelNeedsAnImageButNoneAreSelected ||
|
||||
!selectedModel
|
||||
}
|
||||
{modelNeedsAnImageButNoneAreSelected && (
|
||||
<span className="flex items-center gap-1.5 text-xs text-red-500 font-medium animate-pulse">
|
||||
<FontAwesomeIcon icon={faCircleInfo} />
|
||||
Starting frame required
|
||||
</span>
|
||||
)}
|
||||
<Tooltip
|
||||
content="Add a starting image before generating"
|
||||
position="top"
|
||||
className="z-50"
|
||||
delay={0}
|
||||
disabled={!modelNeedsAnImageButNoneAreSelected}
|
||||
>
|
||||
{isEnqueueing ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faSpinnerThird}
|
||||
className="animate-spin text-lg"
|
||||
/>
|
||||
) : (
|
||||
"Generate"
|
||||
)}
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
className="flex items-center border-none bg-primary px-3 text-sm text-white disabled:cursor-not-allowed disabled:opacity-50"
|
||||
icon={!isEnqueueing ? faSparkles : undefined}
|
||||
onClick={handleEnqueue}
|
||||
disabled={isEnqueueing || !prompt.trim()}
|
||||
>
|
||||
{isEnqueueing ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faSpinnerThird}
|
||||
className="animate-spin text-lg"
|
||||
/>
|
||||
) : (
|
||||
"Generate"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ interface TooltipProps {
|
||||
interactive?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
zIndex?: number;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const Tooltip = ({
|
||||
@@ -32,6 +33,7 @@ export const Tooltip = ({
|
||||
interactive = false,
|
||||
onOpenChange,
|
||||
zIndex = 10,
|
||||
disabled = false,
|
||||
}: TooltipProps) => {
|
||||
const [isShowing, setIsShowing] = useState(false);
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -118,13 +120,17 @@ export const Tooltip = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
setIsShowing(false);
|
||||
return;
|
||||
}
|
||||
if (!checkForOpenPopovers()) {
|
||||
const shouldShow =
|
||||
isHoveringTrigger || (interactive && isHoveringTooltip);
|
||||
setIsShowing(shouldShow);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isHoveringTrigger, isHoveringTooltip, interactive]);
|
||||
}, [isHoveringTrigger, isHoveringTooltip, interactive, disabled]);
|
||||
|
||||
useEffect(() => {
|
||||
onOpenChange?.(isShowing);
|
||||
@@ -135,7 +141,7 @@ export const Tooltip = ({
|
||||
ref={triggerRef}
|
||||
onMouseEnter={() => {
|
||||
setIsHoveringTrigger(true);
|
||||
if (!checkForOpenPopovers()) {
|
||||
if (!checkForOpenPopovers() && !disabled) {
|
||||
setIsShowing(true);
|
||||
}
|
||||
}}
|
||||
|
||||
Reference in new issue
Block a user