diff --git a/app/(app)/tasks/TaskForm.tsx b/app/(app)/tasks/TaskForm.tsx index ea76753..55f2861 100644 --- a/app/(app)/tasks/TaskForm.tsx +++ b/app/(app)/tasks/TaskForm.tsx @@ -5,7 +5,7 @@ "use client"; -import { AlertCircle, X } from "lucide-react"; +import { AlertCircle, Check, X } from "lucide-react"; import { DbTask, TaskStatus } from "@/lib/types/task"; import { useTaskForm } from "./useTaskForm"; import TaskHeader from "./task/TaskHeader"; @@ -98,12 +98,9 @@ export default function TaskForm({ Cancel - + ); diff --git a/app/components/ui/buttons/ActionButton.tsx b/app/components/ui/buttons/ActionButton.tsx index ba18fc3..ca35e74 100644 --- a/app/components/ui/buttons/ActionButton.tsx +++ b/app/components/ui/buttons/ActionButton.tsx @@ -4,39 +4,28 @@ */ import Link from "next/link"; -import { ReactNode } from "react"; +import { ReactNode, ButtonHTMLAttributes } from "react"; import { LucideIcon } from "lucide-react"; -/** - * Properties for the ActionButton component. - * - * @interface ActionButtonProps - * @property {string} href - The target URL path or external link. - * @property {"primary" | "secondary" | "danger"} [variant="primary"] - Visual style variant of the button. - * @property {ReactNode} children - Button label content or child nodes. - * @property {LucideIcon} [icon] - Optional Lucide icon component to display alongside text. - */ -interface ActionButtonProps { - href: string; +interface ActionButtonProps extends ButtonHTMLAttributes { + href?: string; variant?: "primary" | "secondary" | "danger"; children: ReactNode; icon?: LucideIcon; } -/** - * Renders an accessible link styled as an action button with hover states and optional icons. - * - * @param {ActionButtonProps} props - The component props. - * @returns {JSX.Element} The rendered action button link component. - */ export function ActionButton({ href, variant = "primary", children, icon: Icon, + type = "button", + disabled, + className = "", + ...props }: ActionButtonProps) { const baseStyles = - "group w-full sm:w-auto inline-flex items-center justify-center gap-2.5 font-medium transition-all duration-200 ease-out active:scale-[0.97] px-4 py-2.5 rounded-xl text-sm tracking-wide shadow-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 cursor-pointer"; + "group w-full sm:w-auto inline-flex items-center justify-center gap-2.5 font-medium transition-all duration-200 ease-out active:scale-[0.97] px-4 py-2.5 rounded-xl text-sm tracking-wide shadow-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 cursor-pointer disabled:opacity-50 disabled:pointer-events-none"; const variants = { primary: @@ -44,15 +33,38 @@ export function ActionButton({ secondary: "bg-card text-foreground border border-foreground-muted/50 hover:bg-background-muted hover:border-foreground hover:-translate-y-0.5", danger: - "bg-destructive/15 text-destructive border border-destructive/30 hover:bg-destructive hover:text-foreground hover:border-destructive hover:-translate-y-0.5", + "bg-destructive/15 text-destructive border border-destructive/30 hover:bg-destructive hover:text-foreground hover.border-destructive hover:-translate-y-0.5", }; - return ( - + const combinedStyles = `${baseStyles} ${variants[variant]} ${className}`; + + const content = ( + <> {Icon && ( )} {children} - + + ); + + // If an href is passed -> Link button + if (href) { + return ( + + {content} + + ); + } + + // Otherwise, it's a real HTML button + return ( + ); }