diff --git a/frontend/pluto_duck_frontend/app/globals.css b/frontend/pluto_duck_frontend/app/globals.css index c510cac..de2fef0 100644 --- a/frontend/pluto_duck_frontend/app/globals.css +++ b/frontend/pluto_duck_frontend/app/globals.css @@ -274,6 +274,27 @@ animation: stepIn 0.4s cubic-bezier(0.23, 1, 0.32, 1) forwards; } +@keyframes cardIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-card-in { + animation: cardIn 0.5s cubic-bezier(0.23, 1, 0.32, 1) forwards; +} + +@media (prefers-reduced-motion: reduce) { + .animate-card-in { + animation: none !important; + } +} + .animate-text-glow { animation: textGlow 2.2s ease-in-out infinite; } diff --git a/frontend/pluto_duck_frontend/components/ai-elements/todo-checkbox.tsx b/frontend/pluto_duck_frontend/components/ai-elements/todo-checkbox.tsx new file mode 100644 index 0000000..62a4c46 --- /dev/null +++ b/frontend/pluto_duck_frontend/components/ai-elements/todo-checkbox.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { memo, type ComponentProps } from "react"; +import { + getTodoCheckboxContainerClass, + IN_PROGRESS_TODO_GLYPH, + type TodoCheckboxStatus, +} from "./todoCheckboxModel"; + +export type TodoCheckboxProps = ComponentProps<"span"> & { + status?: TodoCheckboxStatus; +}; + +export const TodoCheckbox = memo( + ({ status = "pending", className, ...props }: TodoCheckboxProps) => ( + + {status === "in_progress" ? ( + + {IN_PROGRESS_TODO_GLYPH} + + ) : null} + {status === "completed" ? ( + + + + ) : null} + + ) +); + +TodoCheckbox.displayName = "TodoCheckbox"; diff --git a/frontend/pluto_duck_frontend/components/ai-elements/todoCheckboxModel.ts b/frontend/pluto_duck_frontend/components/ai-elements/todoCheckboxModel.ts new file mode 100644 index 0000000..f00892e --- /dev/null +++ b/frontend/pluto_duck_frontend/components/ai-elements/todoCheckboxModel.ts @@ -0,0 +1,15 @@ +export type TodoCheckboxStatus = "pending" | "in_progress" | "completed"; + +export const IN_PROGRESS_TODO_GLYPH = "\u2734\uFE0E"; + +export function getTodoCheckboxContainerClass( + status: TodoCheckboxStatus +): string { + if (status === "completed") { + return "border-0 bg-muted-foreground/60 text-white"; + } + if (status === "in_progress") { + return "border-[1.5px] border-muted-foreground/50 bg-transparent"; + } + return "border-[1.5px] border-muted-foreground/30 bg-transparent"; +} diff --git a/frontend/pluto_duck_frontend/components/chat/renderers/ApprovalRenderer.tsx b/frontend/pluto_duck_frontend/components/chat/renderers/ApprovalRenderer.tsx index 83d75eb..cdea799 100644 --- a/frontend/pluto_duck_frontend/components/chat/renderers/ApprovalRenderer.tsx +++ b/frontend/pluto_duck_frontend/components/chat/renderers/ApprovalRenderer.tsx @@ -24,9 +24,9 @@ export const ApprovalRenderer = memo(function ApprovalRenderer({ const isPending = item.decision === 'pending'; return ( -
+
- Approval + Approval
-

{summary}

+

+ {summary} +

{isPending && (