mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-25 20:31:13 -05:00
Enhance loading skeletons and breadcrumbs
- Add content-m matching loading skeletons for ParkDetail, RideDetail, CompanyDetail, etc., replacing generic spinners to preserve layout during load - Remove redundant Back to Parent Entity buttons in detail pages in favor of breadcrumb navigation - Prepare groundwork for breadcrumbs across detail pages to improve cohesion and navigation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, lazy, Suspense } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { CompanyDetailSkeleton } from '@/components/loading/CompanyDetailSkeleton';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -150,12 +151,7 @@ export default function DesignerDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -191,13 +187,8 @@ export default function DesignerDetail() {
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate('/designers')}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to Designers
|
||||
</Button>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this designer")}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, lazy, Suspense } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { CompanyDetailSkeleton } from '@/components/loading/CompanyDetailSkeleton';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { trackPageView } from '@/lib/viewTracking';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
@@ -160,12 +161,7 @@ export default function ManufacturerDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -201,14 +197,8 @@ export default function ManufacturerDetail() {
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate('/manufacturers')}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
<span className="md:hidden">Back</span>
|
||||
<span className="hidden md:inline">Back to Manufacturers</span>
|
||||
</Button>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this manufacturer")}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, lazy, Suspense } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { CompanyDetailSkeleton } from '@/components/loading/CompanyDetailSkeleton';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { trackPageView } from '@/lib/viewTracking';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
@@ -189,12 +190,7 @@ export default function OperatorDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -230,13 +226,8 @@ export default function OperatorDetail() {
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate('/operators')}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to Operators
|
||||
</Button>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this operator")}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useParams, useNavigate, Link } from 'react-router-dom';
|
||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
||||
import { CompanyPreviewCard } from '@/components/preview/CompanyPreviewCard';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { ParkDetailSkeleton } from '@/components/loading/ParkDetailSkeleton';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
import { trackPageView } from '@/lib/viewTracking';
|
||||
@@ -164,13 +165,7 @@ export default function ParkDetail() {
|
||||
if (loading) {
|
||||
return <div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
<div className="h-4 bg-muted rounded w-1/3"></div>
|
||||
</div>
|
||||
</div>
|
||||
<ParkDetailSkeleton />
|
||||
</div>;
|
||||
}
|
||||
if (!park) {
|
||||
@@ -203,13 +198,8 @@ export default function ParkDetail() {
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate('/parks')}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to Parks
|
||||
</Button>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditParkModalOpen(true), "Sign in to edit this park")}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState, useEffect, lazy, Suspense } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { CompanyDetailSkeleton } from '@/components/loading/CompanyDetailSkeleton';
|
||||
import { trackPageView } from '@/lib/viewTracking';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -188,12 +190,7 @@ export default function PropertyOwnerDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -220,13 +217,17 @@ export default function PropertyOwnerDetail() {
|
||||
<Header />
|
||||
|
||||
<main className="container mx-auto px-4 py-8 max-w-7xl">
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate('/owners')}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to Property Owners
|
||||
</Button>
|
||||
|
||||
{/* Breadcrumb Navigation */}
|
||||
<EntityBreadcrumb
|
||||
segments={[
|
||||
{ label: 'Property Owners', href: '/owners' },
|
||||
{ label: owner.name }
|
||||
]}
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this property owner")}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/h
|
||||
import { CompanyPreviewCard } from '@/components/preview/CompanyPreviewCard';
|
||||
import { ParkPreviewCard } from '@/components/preview/ParkPreviewCard';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { RideDetailSkeleton } from '@/components/loading/RideDetailSkeleton';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
|
||||
import { trackPageView } from '@/lib/viewTracking';
|
||||
@@ -164,13 +165,7 @@ export default function RideDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-64 bg-muted rounded-lg"></div>
|
||||
<div className="h-8 bg-muted rounded w-1/2"></div>
|
||||
<div className="h-4 bg-muted rounded w-1/3"></div>
|
||||
</div>
|
||||
</div>
|
||||
<RideDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -217,16 +212,8 @@ export default function RideDetail() {
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Back Button and Edit Button */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/parks/${ride.park?.slug}`)}
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to {ride.park?.name}
|
||||
</Button>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this ride")}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState, useEffect, useCallback, lazy, Suspense } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { EntityBreadcrumb } from '@/components/navigation/EntityBreadcrumb';
|
||||
import { CompanyDetailSkeleton } from '@/components/loading/CompanyDetailSkeleton';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
@@ -167,17 +169,7 @@ export default function RideModelDetail() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="animate-pulse space-y-6">
|
||||
<div className="h-12 bg-muted rounded w-1/3"></div>
|
||||
<div className="h-64 bg-muted rounded"></div>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{[...Array(6)].map((_, i) => (
|
||||
<div key={i} className="h-48 bg-muted rounded-lg"></div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDetailSkeleton />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -204,12 +196,25 @@ export default function RideModelDetail() {
|
||||
<Header />
|
||||
|
||||
<main className="container mx-auto px-4 py-8">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Button variant="ghost" onClick={() => navigate(`/manufacturers/${manufacturerSlug}/models`)}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Back to {manufacturer.name} Models
|
||||
</Button>
|
||||
|
||||
{/* Breadcrumb Navigation */}
|
||||
<EntityBreadcrumb
|
||||
segments={[
|
||||
{ label: 'Manufacturers', href: '/manufacturers' },
|
||||
{
|
||||
label: manufacturer.name,
|
||||
href: `/manufacturers/${manufacturerSlug}`,
|
||||
showPreview: true,
|
||||
previewType: 'company',
|
||||
previewSlug: manufacturerSlug || ''
|
||||
},
|
||||
{ label: 'Models', href: `/manufacturers/${manufacturerSlug}/models` },
|
||||
{ label: model.name }
|
||||
]}
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Edit Button */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => requireAuth(() => setIsEditModalOpen(true), "Sign in to edit this ride model")}
|
||||
|
||||
Reference in New Issue
Block a user