flowstate/app/components/ui/buttons/GoBackButton.tsx
Chneemann d6209c900d
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 59s
feat(ui): add GoBackButton component with animated hover and history check
2026-08-16 19:19:29 +02:00

85 lines
2.5 KiB
TypeScript

/**
* @file components/ui/buttons/GoBackButton.tsx
* @description Client component rendering an interactive back button with intelligent history checking and animated hover effects.
*/
"use client";
import { useRouter } from "next/navigation";
import { ArrowLeft } from "lucide-react";
import { ComponentPropsWithoutRef } from "react";
/**
* Properties for the GoBackButton component.
*
* @interface GoBackButtonProps
* @extends {ComponentPropsWithoutRef<"button">}
* @property {string} [fallbackUrl] - The backup route URL to navigate to if no browser history exists.
* @property {string} [label] - The text label displayed next to the arrow icon.
*/
interface GoBackButtonProps extends ComponentPropsWithoutRef<"button"> {
fallbackUrl?: string;
label?: string;
}
/**
* Renders a back button that navigates to the previous history entry if available,
* or falls back to a default URL, featuring an animated left arrow icon and underline effects.
*
* @param {GoBackButtonProps} props - The component props.
* @returns {JSX.Element} The rendered go back button component.
*/
export function GoBackButton({
fallbackUrl = "/",
label = "previous page",
className = "",
onClick,
...props
}: GoBackButtonProps) {
const router = useRouter();
/**
* Handles the click event, triggering custom click actions if provided,
* and determining whether to pop history or redirect to the fallback URL.
*
* @param {React.MouseEvent<HTMLButtonElement>} e - The mouse event object.
*/
const handleBack = (e: React.MouseEvent<HTMLButtonElement>) => {
if (onClick) {
onClick(e);
}
if (e.defaultPrevented) return;
e.preventDefault();
const hasHistory = window.history.state && window.history.state.idx > 0;
if (hasHistory) {
router.back();
} else {
router.push(fallbackUrl);
}
};
return (
<button
type="button"
onClick={handleBack}
className={`inline-flex items-center gap-2 text-xs text-primary hover:text-primary-hover transition-colors group bg-transparent border-none p-0 cursor-pointer ${className}`}
{...props}
>
<ArrowLeft
size={14}
aria-hidden="true"
className="group-hover:-translate-x-1 transition-transform shrink-0"
/>
<span className="relative pb-0.5">
Back to {label}
<span
className="absolute left-0 bottom-0 h-px w-0 bg-primary transition-all duration-300 ease-in-out group-hover:w-full"
aria-hidden="true"
/>
</span>
</button>
);
}