refactor(ui): update ActionButton icon placement and refine Link rendering
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 46s
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 46s
This commit is contained in:
parent
587d54865f
commit
d5bae440fd
1 changed files with 17 additions and 13 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @file app/components/ui/buttons/ActionButton.tsx
|
* @file app/components/ui/buttons/ActionButton.tsx
|
||||||
* @description Client/Server UI component rendering a styled link button with customizable variants and optional Lucide icons.
|
* @description UI component rendering a styled link button or native button with customizable variants and optional Lucide icons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -12,22 +12,25 @@ import { LucideIcon } from "lucide-react";
|
||||||
*
|
*
|
||||||
* @interface ActionButtonProps
|
* @interface ActionButtonProps
|
||||||
* @extends {ButtonHTMLAttributes<HTMLButtonElement>}
|
* @extends {ButtonHTMLAttributes<HTMLButtonElement>}
|
||||||
* @property {string} [href] - Optional navigation target URL. Renders a Next.js Link component if defined.
|
*
|
||||||
* @property {"primary" | "secondary" | "danger"} [variant="primary"] - Visual style variant of the button.
|
* @property {string} [href] Optional navigation target URL. Renders a Next.js Link component if defined.
|
||||||
* @property {ReactNode} children - Button label content or child nodes.
|
* @property {"primary" | "secondary" | "danger"} [variant="primary"] Visual style variant of the button.
|
||||||
* @property {LucideIcon} [icon] - Optional Lucide icon component to display alongside the text label.
|
* @property {ReactNode} children Button label content or child nodes.
|
||||||
|
* @property {LucideIcon} [icon] Optional Lucide icon component to display alongside the text label.
|
||||||
|
* @property {"start" | "end"} [iconPosition="end"] Explicitly sets the icon position (defaults to "end").
|
||||||
*/
|
*/
|
||||||
interface ActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
interface ActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
href?: string;
|
href?: string;
|
||||||
variant?: "primary" | "secondary" | "danger";
|
variant?: "primary" | "secondary" | "danger";
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
icon?: LucideIcon;
|
icon?: LucideIcon;
|
||||||
|
iconPosition?: "start" | "end";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a customizable button or link element styled with Tailwind CSS, supporting variants, icons, and disabled states.
|
* Renders a customizable button or link element styled with Tailwind CSS, supporting variants, icons, and disabled states.
|
||||||
*
|
*
|
||||||
* @param {ActionButtonProps} props - The component props.
|
* @param {ActionButtonProps} props The component props.
|
||||||
* @returns {JSX.Element} The rendered button or link component.
|
* @returns {JSX.Element} The rendered button or link component.
|
||||||
*/
|
*/
|
||||||
export function ActionButton({
|
export function ActionButton({
|
||||||
|
|
@ -35,6 +38,7 @@ export function ActionButton({
|
||||||
variant = "primary",
|
variant = "primary",
|
||||||
children,
|
children,
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
|
iconPosition = "start",
|
||||||
type = "button",
|
type = "button",
|
||||||
disabled,
|
disabled,
|
||||||
className = "",
|
className = "",
|
||||||
|
|
@ -49,17 +53,20 @@ export function ActionButton({
|
||||||
secondary:
|
secondary:
|
||||||
"bg-card text-foreground border border-foreground-muted/50 hover:bg-background-muted hover:border-foreground hover:-translate-y-0.5",
|
"bg-card text-foreground border border-foreground-muted/50 hover:bg-background-muted hover:border-foreground hover:-translate-y-0.5",
|
||||||
danger:
|
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",
|
||||||
};
|
};
|
||||||
|
|
||||||
const combinedStyles = `${baseStyles} ${variants[variant]} ${className}`;
|
const combinedStyles = `${baseStyles} ${variants[variant]} ${className}`;
|
||||||
|
|
||||||
|
const renderIcon = Icon ? (
|
||||||
|
<Icon className="w-4 h-4 transition-transform duration-200 ease-out group-hover:scale-110 shrink-0" />
|
||||||
|
) : null;
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<>
|
<>
|
||||||
{Icon && (
|
{iconPosition === "start" && renderIcon}
|
||||||
<Icon className="w-4 h-4 transition-transform duration-200 ease-out group-hover:scale-110 shrink-0" />
|
|
||||||
)}
|
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
|
{iconPosition === "end" && renderIcon}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -69,9 +76,6 @@ export function ActionButton({
|
||||||
<Link
|
<Link
|
||||||
href={disabled ? "#" : href}
|
href={disabled ? "#" : href}
|
||||||
aria-disabled={disabled}
|
aria-disabled={disabled}
|
||||||
onClick={(e) => {
|
|
||||||
if (disabled) e.preventDefault();
|
|
||||||
}}
|
|
||||||
className={`${combinedStyles} ${
|
className={`${combinedStyles} ${
|
||||||
disabled ? "pointer-events-none opacity-50" : ""
|
disabled ? "pointer-events-none opacity-50" : ""
|
||||||
}`}
|
}`}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue