Made animations with X and Check

This commit is contained in:
Lucas Oliveira 2024-02-26 20:16:56 +01:00
commit efd4f80dcd
5 changed files with 169 additions and 71 deletions

View file

@ -44,6 +44,7 @@
"clsx": "^1.2.1",
"dompurify": "^3.0.5",
"esbuild": "^0.17.19",
"framer-motion": "^11.0.6",
"lodash": "^4.17.21",
"lucide-react": "^0.331.0",
"moment": "^2.29.4",
@ -5918,6 +5919,44 @@
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/framer-motion": {
"version": "11.0.6",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.6.tgz",
"integrity": "sha512-BpO3mWF8UwxzO3Ca5AmSkrg14QYTeJa9vKgoLOoBdBdTPj0e81i1dMwnX6EQJXRieUx20uiDBXq8bA6y7N6b8Q==",
"dependencies": {
"tslib": "^2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/framer-motion/node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/framer-motion/node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"node_modules/fs-extra": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",

View file

@ -39,6 +39,7 @@
"clsx": "^1.2.1",
"dompurify": "^3.0.5",
"esbuild": "^0.17.19",
"framer-motion": "^11.0.6",
"lodash": "^4.17.21",
"lucide-react": "^0.331.0",
"moment": "^2.29.4",

View file

@ -4,6 +4,7 @@ import ShadTooltip from "../../components/ShadTooltipComponent";
import IconComponent from "../../components/genericIconComponent";
import InputComponent from "../../components/inputComponent";
import { Button } from "../../components/ui/button";
import Checkmark from "../../components/ui/checkmark";
import Loading from "../../components/ui/loading";
import { Textarea } from "../../components/ui/textarea";
import { priorityFields } from "../../constants/constants";
@ -19,6 +20,7 @@ import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, cn, getFieldTitle } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent";
import Xmark from "../../components/ui/xmark";
export default function GenericNode({
data,
@ -118,7 +120,7 @@ export default function GenericNode({
} else {
setValidationStatus(null);
}
}, [flowPool, data.id]);
}, [flowPool[data.id], data.id]);
const showNode = data.showNode ?? true;
@ -156,52 +158,44 @@ export default function GenericNode({
);
};
const getIconPlayOrPauseComponent = (name, className) => (
<IconComponent
name={name}
className={`h-4 fill-current stroke-2 ${className}`}
/>
);
const getStatusClassName = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
console.log(buildStatus);
const isValid = validationStatus && validationStatus.valid;
if (isValid) {
return "green-status";
} else if (!isValid && buildStatus === BuildStatus.INACTIVE) {
return "gray-status";
} else if (!validationStatus && buildStatus === BuildStatus.BUILT) {
return "green-status";
} else if (!isValid && buildStatus === BuildStatus.BUILT) {
return "red-status";
} else if (!validationStatus && buildStatus === BuildStatus.TO_BUILD) {
return "green-status";
} else {
return "yellow-status";
}
};
const isDark = useDarkStore((state) => state.dark);
const renderIconStatusComponents = (
const renderIconStatus = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
const className = getStatusClassName(buildStatus, validationStatus);
return <>{getIconPlayOrPauseComponent("CircleDot", className)}</>;
};
const renderIconPlayOrPauseComponents = (
buildStatus: BuildStatus | undefined,
) => {
if (buildStatus === BuildStatus.BUILDING) {
return <Loading />;
return <Loading className="text-medium-indigo" />;
} else {
return (
<IconComponent
name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-muted-foreground group-hover:text-medium-indigo"
/>
<>
<IconComponent
name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-medium-indigo opacity-0 transition-all group-hover:opacity-100"
/>
{validationStatus && validationStatus.valid ? (
<Checkmark
className="absolute ml-0.5 h-5 stroke-2 text-status-green opacity-100 transition-all group-hover:opacity-0"
isVisible={true}
/>
) : validationStatus &&
!validationStatus.valid &&
buildStatus === BuildStatus.INACTIVE ? (
<IconComponent
name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-green opacity-30 transition-all group-hover:opacity-0"
/>
) : validationStatus && !validationStatus.valid ? (
<Xmark
isVisible={true}
className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-red opacity-100 transition-all group-hover:opacity-0"
/>
) : (
<IconComponent
name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-muted-foreground opacity-100 transition-all group-hover:opacity-0"
/>
)}
</>
);
}
};
@ -467,53 +461,40 @@ export default function GenericNode({
variant="secondary"
className={"group h-9 px-1.5"}
onClick={() => {
if (data?.buildStatus === BuildStatus.BUILDING || isBuilding)
if (buildStatus === BuildStatus.BUILDING || isBuilding)
return;
setValidationStatus(null);
buildFlow(data.id);
}}
>
<div>
<ShadTooltip
content={
"Build"
buildStatus === BuildStatus.BUILDING ? (
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">Build to validate status.</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? `${durationString}\n${validationStatus.params}`
.split("\n")
.map((line, index) => (
<div key={index}>{line}</div>
))
: durationString}
</div>
)
}
side="bottom"
>
<div className="generic-node-status-position flex items-center justify-center">
{renderIconPlayOrPauseComponents(
buildStatus,
)}
{renderIconStatus(buildStatus, validationStatus)}
</div>
</ShadTooltip>
</div>
</Button>
)}
<div className="">
<ShadTooltip
content={
data?.buildStatus === BuildStatus.BUILDING ? (
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">Build to validate status.</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? `${durationString}\n${validationStatus.params}`
.split("\n")
.map((line, index) => <div key={index}>{line}</div>)
: durationString}
</div>
)
}
>
<div>
{renderIconStatusComponents(
data?.buildStatus,
validationStatus
)}
</div>
</ShadTooltip>
</div>
</div>
</div>

View file

@ -0,0 +1,31 @@
import { AnimatePresence, motion } from "framer-motion";
export default function Checkmark({ initial = true, isVisible, className }) {
return (
<AnimatePresence initial={initial}>
{isVisible && (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className={"CheckIcon " + className}
>
<motion.path
initial={{ pathLength: 0, pathOffset: 1 }}
animate={{ pathLength: 1, pathOffset: 0 }}
exit={{ pathLength: 0, pathOffset: 1 }}
transition={{
type: "tween",
duration: 0.3,
ease: isVisible ? "easeOut" : "easeIn",
}}
strokeLinecap="round"
strokeLinejoin="round"
d="M20 6 9 17l-5-5"
/>
</svg>
)}
</AnimatePresence>
);
}

View file

@ -0,0 +1,46 @@
import { AnimatePresence, motion } from "framer-motion";
export default function Xmark({ initial = true, isVisible, className }) {
return (
<AnimatePresence initial={initial}>
{isVisible && (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className={"CheckIcon " + className}
>
<motion.path
initial={{ pathLength: 0, pathOffset: 1, strokeLinecap: "butt" }}
animate={{ pathLength: 1, pathOffset: 0, strokeLinecap: "round" }}
exit={{ pathLength: 0, pathOffset: 1, strokeLinecap: "butt" }}
transition={{
type: "tween",
duration: 0.3,
ease: isVisible ? "easeOut" : "easeIn",
delay: 0.2,
}}
strokeLinecap="round"
strokeLinejoin="round"
d="M18 6 6 18"
/>
<motion.path
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
exit={{ pathLength: 0 }}
transition={{
type: "tween",
duration: 0.3,
ease: isVisible ? "easeOut" : "easeIn",
}}
strokeLinecap="round"
strokeLinejoin="round"
d="m6 6 12 12"
/>
</svg>
)}
</AnimatePresence>
);
}