UI design of button and repeat function

This commit is contained in:
Lucas Oliveira 2024-01-26 19:51:27 +01:00
commit e606762e7f
4 changed files with 124 additions and 104 deletions

View file

@ -4,6 +4,7 @@ import ShadTooltip from "../../components/ShadTooltipComponent";
import Tooltip from "../../components/TooltipComponent"; import Tooltip from "../../components/TooltipComponent";
import IconComponent from "../../components/genericIconComponent"; import IconComponent from "../../components/genericIconComponent";
import InputComponent from "../../components/inputComponent"; import InputComponent from "../../components/inputComponent";
import { Button } from "../../components/ui/button";
import { Textarea } from "../../components/ui/textarea"; import { Textarea } from "../../components/ui/textarea";
import { priorityFields } from "../../constants/constants"; import { priorityFields } from "../../constants/constants";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent"; import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
@ -320,8 +321,9 @@ export default function GenericNode({
)} )}
</div> </div>
{showNode && ( {showNode && (
<div <Button
className="round-button-div" variant="outline"
className="h-9 px-1.5"
onClick={() => { onClick={() => {
setNode(data.id, (old) => ({ setNode(data.id, (old) => ({
...old, ...old,
@ -346,11 +348,12 @@ export default function GenericNode({
/> />
</div> </div>
</Tooltip> </Tooltip>
</div> </Button>
)} )}
{showNode && ( {showNode && (
<div <Button
className="round-button-div" variant="outline"
className="h-9 px-1.5"
onClick={() => buildFlow(data.id)} onClick={() => buildFlow(data.id)}
> >
<div> <div>
@ -363,7 +366,7 @@ export default function GenericNode({
Build{" "} Build{" "}
<IconComponent <IconComponent
name="Zap" name="Zap"
className="mx-0.5 h-5 fill-build-trigger stroke-build-trigger stroke-1" className=" h-5 fill-build-trigger stroke-build-trigger stroke-1"
/>{" "} />{" "}
flow to validate status. flow to validate status.
</span> </span>
@ -381,34 +384,37 @@ export default function GenericNode({
} }
> >
<div className="generic-node-status-position flex items-center"> <div className="generic-node-status-position flex items-center">
<div <IconComponent
name="Zap"
className={classNames( className={classNames(
validationStatus && validationStatus.valid validationStatus && validationStatus.valid
? "green-status" ? "green-status"
: "status-build-animation", : "status-build-animation",
"status-div" "h-5 stroke-1"
)} )}
></div> />
<div <IconComponent
name="Zap"
className={classNames( className={classNames(
validationStatus && !validationStatus.valid validationStatus && !validationStatus.valid
? "red-status" ? "red-status"
: "status-build-animation", : "status-build-animation",
"status-div" "h-5 stroke-1"
)} )}
></div> />
<div <IconComponent
name="Zap"
className={classNames( className={classNames(
!validationStatus || isBuilding !validationStatus || isBuilding
? "yellow-status" ? "yellow-status"
: "status-build-animation", : "status-build-animation",
"status-div" "h-5 stroke-1"
)} )}
></div> />
</div> </div>
</Tooltip> </Tooltip>
</div> </div>
</div> </Button>
)} )}
</div> </div>
</div> </div>

View file

@ -3,6 +3,9 @@ import IconComponent from "../../../components/genericIconComponent";
import { Textarea } from "../../../components/ui/textarea"; import { Textarea } from "../../../components/ui/textarea";
import { chatInputType } from "../../../types/components"; import { chatInputType } from "../../../types/components";
import { classNames } from "../../../utils/utils"; import { classNames } from "../../../utils/utils";
import { Button } from "../../ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover";
import { Input } from "../../ui/input";
export default function ChatInput({ export default function ChatInput({
lockChat, lockChat,
@ -12,7 +15,7 @@ export default function ChatInput({
inputRef, inputRef,
noInput, noInput,
}: chatInputType): JSX.Element { }: chatInputType): JSX.Element {
const [repeate, setRepeate] = useState(1); const [repeat, setRepeat] = useState(1);
useEffect(() => { useEffect(() => {
if (!lockChat && inputRef.current) { if (!lockChat && inputRef.current) {
inputRef.current.focus(); inputRef.current.focus();
@ -22,9 +25,9 @@ export default function ChatInput({
function handleChange(value: number) { function handleChange(value: number) {
console.log(value); console.log(value);
if (value > 0) { if (value > 0) {
setRepeate(value); setRepeat(value);
} else { } else {
setRepeate(1); setRepeat(1);
} }
} }
@ -36,90 +39,99 @@ export default function ChatInput({
}, [chatValue]); }, [chatValue]);
return ( return (
<div className="relative"> <div className="flex w-full gap-2">
<div className="flex flex-col"> <div className="relative w-full">
<span className="text-xs">repeate</span> <Textarea
<input onKeyDown={(event) => {
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
sendMessage(repeat);
}
}}
rows={1}
ref={inputRef}
disabled={lockChat || noInput}
style={{
resize: "none",
bottom: `${inputRef?.current?.scrollHeight}px`,
maxHeight: "150px",
overflow: `${
inputRef.current && inputRef.current.scrollHeight > 150
? "auto"
: "hidden"
}`,
}}
value={lockChat ? "Thinking..." : chatValue}
onChange={(event): void => {
setChatValue(event.target.value);
}}
className={classNames(
lockChat
? " form-modal-lock-true bg-input"
: noInput
? "form-modal-no-input bg-input"
: " form-modal-lock-false bg-background",
"form-modal-lockchat"
)}
placeholder={
noInput
? "No chat input variables found. Click to run your flow."
: "Send a message..."
}
/>
<div className="form-modal-send-icon-position">
<button
className={classNames(
"form-modal-send-button",
noInput
? "bg-high-indigo text-background"
: chatValue === ""
? "text-primary"
: "bg-chat-send text-background"
)}
disabled={lockChat}
onClick={(): void => sendMessage()}
>
{lockChat ? (
<IconComponent
name="Lock"
className="form-modal-lock-icon"
aria-hidden="true"
/>
) : noInput ? (
<IconComponent
name="Sparkles"
className="form-modal-play-icon"
aria-hidden="true"
/>
) : (
<IconComponent
name="LucideSend"
className="form-modal-send-icon "
aria-hidden="true"
/>
)}
</button>
</div>
</div>
<Popover>
<PopoverTrigger asChild>
<Button variant="primary" className="h-13 px-4">
<IconComponent name="Repeat" className="" aria-hidden="true" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-fit"><div className="flex flex-col gap-2 items-center justify-center">
<span className="text-sm">Repetitions: </span>
<Input
onChange={(e) => { onChange={(e) => {
handleChange(parseInt(e.target.value)); handleChange(parseInt(e.target.value));
}} }}
className="bg-background" className="w-16"
type="number" type="number"
min={0} min={0}
/> />
</div> </div></PopoverContent>
<Textarea </Popover>
onKeyDown={(event) => {
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
sendMessage(repeate);
}
}}
rows={1}
ref={inputRef}
disabled={lockChat || noInput}
style={{
resize: "none",
bottom: `${inputRef?.current?.scrollHeight}px`,
maxHeight: "150px",
overflow: `${
inputRef.current && inputRef.current.scrollHeight > 150
? "auto"
: "hidden"
}`,
}}
value={lockChat ? "Thinking..." : chatValue}
onChange={(event): void => {
setChatValue(event.target.value);
}}
className={classNames(
lockChat
? " form-modal-lock-true bg-input"
: noInput
? "form-modal-no-input bg-input"
: " form-modal-lock-false bg-background",
"form-modal-lockchat"
)}
placeholder={
noInput
? "No chat input variables found. Click to run your flow."
: "Send a message..."
}
/>
<div className="form-modal-send-icon-position">
<button
className={classNames(
"form-modal-send-button",
noInput
? "bg-high-indigo text-background"
: chatValue === ""
? "text-primary"
: "bg-chat-send text-background"
)}
disabled={lockChat}
onClick={(): void => sendMessage()}
>
{lockChat ? (
<IconComponent
name="Lock"
className="form-modal-lock-icon"
aria-hidden="true"
/>
) : noInput ? (
<IconComponent
name="Sparkles"
className="form-modal-play-icon"
aria-hidden="true"
/>
) : (
<IconComponent
name="LucideSend"
className="form-modal-send-icon "
aria-hidden="true"
/>
)}
</button>
</div>
</div> </div>
); );
} }

View file

@ -267,7 +267,7 @@
@apply relative flex flex-col justify-center bg-background; @apply relative flex flex-col justify-center bg-background;
} }
.generic-node-div-title { .generic-node-div-title {
@apply flex w-full items-center gap-4 border-b bg-muted p-4; @apply flex w-full items-center gap-2 border-b bg-muted p-4;
} }
.generic-node-title-arrangement { .generic-node-title-arrangement {
@apply flex-max-width items-center truncate; @apply flex-max-width items-center truncate;
@ -283,26 +283,26 @@
} }
.generic-node-status-position { .generic-node-status-position {
@apply relative top-[3px] h-5 w-5; @apply h-5 w-5;
} }
.generic-node-status-animation { .generic-node-status-animation {
@apply hidden h-4 w-4 animate-spin rounded-full bg-ring opacity-0; @apply hidden h-4 w-4 animate-spin rounded-full bg-ring opacity-0;
} }
.generic-node-status { .generic-node-status {
@apply h-4 w-4 rounded-full opacity-100; @apply opacity-100;
} }
.green-status { .green-status {
@apply generic-node-status bg-status-green; @apply generic-node-status text-status-green fill-status-green;
} }
.red-status { .red-status {
@apply generic-node-status bg-status-red; @apply generic-node-status text-status-red fill-status-red;
} }
.yellow-status { .yellow-status {
@apply generic-node-status bg-status-yellow; @apply generic-node-status text-status-yellow fill-status-yellow;
} }
.status-build-animation { .status-build-animation {
@apply hidden h-4 w-4 animate-spin rounded-full bg-ring opacity-0; @apply hidden animate-spin text-ring opacity-0;
} }
.status-div { .status-div {
@apply absolute w-4 duration-200 ease-in-out; @apply absolute w-4 duration-200 ease-in-out;

View file

@ -72,6 +72,7 @@ import {
Plus, Plus,
Redo, Redo,
RefreshCcw, RefreshCcw,
Repeat,
Rocket, Rocket,
Save, Save,
SaveAll, SaveAll,
@ -385,5 +386,6 @@ export const nodeIconsLucide: iconsType = {
RefreshCcw, RefreshCcw,
Combine, Combine,
TerminalIcon, TerminalIcon,
Repeat,
io: ArrowDownUp, io: ArrowDownUp,
}; };