Add breadcrumb and transitions

Introduce breadcrumb navigation component and integrate into detail pages with hover previews; add PageTransition to App for smooth navigations and loading animations.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-12 03:46:34 +00:00
parent 361231bfac
commit fdfa1739e5
8 changed files with 186 additions and 4 deletions

View File

@@ -0,0 +1,34 @@
import { ReactNode, useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
interface PageTransitionProps {
children: ReactNode;
}
export function PageTransition({ children }: PageTransitionProps) {
const location = useLocation();
const [displayLocation, setDisplayLocation] = useState(location);
const [transitionStage, setTransitionStage] = useState<'fade-in' | 'fade-out'>('fade-in');
useEffect(() => {
if (location !== displayLocation) {
setTransitionStage('fade-out');
}
}, [location, displayLocation]);
const onAnimationEnd = () => {
if (transitionStage === 'fade-out') {
setTransitionStage('fade-in');
setDisplayLocation(location);
}
};
return (
<div
className={`${transitionStage === 'fade-out' ? 'animate-fade-out' : 'animate-fade-in'}`}
onAnimationEnd={onAnimationEnd}
>
{children}
</div>
);
}

View File

@@ -0,0 +1,87 @@
import { Link } from 'react-router-dom';
import { Home } from 'lucide-react';
import {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/components/ui/breadcrumb';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
import { ParkPreviewCard } from '@/components/preview/ParkPreviewCard';
import { CompanyPreviewCard } from '@/components/preview/CompanyPreviewCard';
interface BreadcrumbSegment {
label: string;
href?: string;
showPreview?: boolean;
previewType?: 'park' | 'company';
previewSlug?: string;
}
interface EntityBreadcrumbProps {
segments: BreadcrumbSegment[];
className?: string;
}
export function EntityBreadcrumb({ segments, className }: EntityBreadcrumbProps) {
return (
<Breadcrumb className={className}>
<BreadcrumbList>
{/* Home link */}
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to="/" className="flex items-center gap-1 hover:text-primary transition-colors">
<Home className="w-3.5 h-3.5" />
<span>Home</span>
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
{segments.map((segment, index) => {
const isLast = index === segments.length - 1;
return (
<BreadcrumbItem key={index}>
<BreadcrumbSeparator />
{isLast ? (
<BreadcrumbPage>{segment.label}</BreadcrumbPage>
) : segment.showPreview && segment.previewSlug ? (
<HoverCard openDelay={300}>
<HoverCardTrigger asChild>
<BreadcrumbLink asChild>
<Link
to={segment.href || '#'}
className="hover:text-primary transition-colors"
>
{segment.label}
</Link>
</BreadcrumbLink>
</HoverCardTrigger>
<HoverCardContent side="bottom" align="start" className="w-auto">
{segment.previewType === 'park' && (
<ParkPreviewCard slug={segment.previewSlug} />
)}
{segment.previewType === 'company' && (
<CompanyPreviewCard slug={segment.previewSlug} />
)}
</HoverCardContent>
</HoverCard>
) : (
<BreadcrumbLink asChild>
<Link
to={segment.href || '#'}
className="hover:text-primary transition-colors"
>
{segment.label}
</Link>
</BreadcrumbLink>
)}
</BreadcrumbItem>
);
})}
</BreadcrumbList>
</Breadcrumb>
);
}