feat(ui): add GoBackButton component with animated hover and history check
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 59s
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 59s
This commit is contained in:
parent
60e2b77324
commit
d6209c900d
4 changed files with 95 additions and 13 deletions
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ArrowLeft, Trash2 } from "lucide-react";
|
import { GoBackButton } from "@/app/components/ui/buttons/GoBackButton";
|
||||||
import Link from "next/link";
|
import { Trash2 } from "lucide-react";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the trash page header featuring title details, an indicator icon,
|
* Renders the trash page header featuring title details, an indicator icon,
|
||||||
|
|
@ -29,16 +29,7 @@ export default function TrashHeader() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<GoBackButton fallbackUrl="/dashboard" label="Dashboard" />
|
||||||
href="/dashboard"
|
|
||||||
className="inline-flex items-center gap-2 text-xs text-primary hover:text-primary-hover transition-colors mb-6 group"
|
|
||||||
>
|
|
||||||
<ArrowLeft
|
|
||||||
size={14}
|
|
||||||
className="group-hover:-translate-x-1 transition-transform"
|
|
||||||
/>
|
|
||||||
Back to Dashboard
|
|
||||||
</Link>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
85
app/components/ui/buttons/GoBackButton.tsx
Normal file
85
app/components/ui/buttons/GoBackButton.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
* @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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
* @description Server component rendering the legal notice (imprint) page with a title header and back button navigation.
|
* @description Server component rendering the legal notice (imprint) page with a title header and back button navigation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { GoBackButton } from "../components/ui/buttons/GoBackButton";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the imprint/legal notice page containing the main title and layout container.
|
* Renders the imprint/legal notice page containing the main title and layout container.
|
||||||
*
|
*
|
||||||
|
|
@ -16,6 +18,7 @@ export default async function ImprintPage() {
|
||||||
<h1 className="text-2xl font-bold text-foreground mb-1 tracking-tight">
|
<h1 className="text-2xl font-bold text-foreground mb-1 tracking-tight">
|
||||||
Legal Notice<span className="text-primary">.</span>
|
Legal Notice<span className="text-primary">.</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
<GoBackButton />
|
||||||
<div className="space-y-6 text-sm mt-3 text-foreground-muted leading-relaxed">
|
<div className="space-y-6 text-sm mt-3 text-foreground-muted leading-relaxed">
|
||||||
{/* Information in accordance with § 5 DDG & § 18 MStV */}
|
{/* Information in accordance with § 5 DDG & § 18 MStV */}
|
||||||
<div className="rounded-2xl border border-border bg-card p-6 shadow-xl space-y-3">
|
<div className="rounded-2xl border border-border bg-card p-6 shadow-xl space-y-3">
|
||||||
|
|
@ -23,7 +26,7 @@ export default async function ImprintPage() {
|
||||||
<span className="text-primary">//</span> Information Pursuant to §
|
<span className="text-primary">//</span> Information Pursuant to §
|
||||||
5 DDG
|
5 DDG
|
||||||
</h2>
|
</h2>
|
||||||
<div className="font-mono text-xs bg-background/60 p-4 rounded-xl border border-border text-foreground space-y-1">
|
<div className="font-mono text-xs bg-background/60 p-4 rounded-xl border border-border text-foreground">
|
||||||
<p className="font-semibold">André Kempf</p>
|
<p className="font-semibold">André Kempf</p>
|
||||||
<p className="text-primary-hover">Full-Stack Web Developer</p>
|
<p className="text-primary-hover">Full-Stack Web Developer</p>
|
||||||
<p>Großschneidersweg 2a</p>
|
<p>Großschneidersweg 2a</p>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
* @description Server component rendering the privacy policy page with a title header and back button navigation.
|
* @description Server component rendering the privacy policy page with a title header and back button navigation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { GoBackButton } from "../components/ui/buttons/GoBackButton";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the privacy policy page containing the main title and layout container alongside a back navigation button.
|
* Renders the privacy policy page containing the main title and layout container alongside a back navigation button.
|
||||||
*
|
*
|
||||||
|
|
@ -16,6 +18,7 @@ export default async function PrivacyPage() {
|
||||||
<h1 className="text-2xl font-bold text-foreground mb-1 tracking-tight">
|
<h1 className="text-2xl font-bold text-foreground mb-1 tracking-tight">
|
||||||
Privacy Policy<span className="text-primary">.</span>
|
Privacy Policy<span className="text-primary">.</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
<GoBackButton />
|
||||||
<div className="space-y-6 text-sm mt-3 text-foreground-muted leading-relaxed">
|
<div className="space-y-6 text-sm mt-3 text-foreground-muted leading-relaxed">
|
||||||
{/* Overview */}
|
{/* Overview */}
|
||||||
<div className="rounded-2xl border border-border bg-card p-6 shadow-xl space-y-4">
|
<div className="rounded-2xl border border-border bg-card p-6 shadow-xl space-y-4">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue