Add hover preview cards

Adds hover-preview UX by introducing preview cards for entities and wiring hoverable links:
- Implements CompanyPreviewCard and ParkPreviewCard components plus hooks to fetch preview data
- Adds HoverCard usage to ParkDetail and RideDetail for operator, manufacturer, and designer links
- Creates preview wrappers for manufacturer/designer/operator links and updates related pages to use hover previews
- Includes supporting updates to query keys and preview hooks to fetch minimal data for previews
This commit is contained in:
gpt-engineer-app[bot]
2025-11-12 03:44:01 +00:00
parent 2ccfe8c48a
commit 361231bfac
8 changed files with 345 additions and 28 deletions

View File

@@ -0,0 +1,36 @@
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/lib/supabaseClient';
import { queryKeys } from '@/lib/queryKeys';
/**
* Hook to fetch company preview data for hover cards
*/
export function useCompanyPreview(slug: string | undefined, enabled = true) {
return useQuery({
queryKey: queryKeys.companies.detail(slug || ''),
queryFn: async () => {
if (!slug) throw new Error('Slug is required');
const { data, error } = await supabase
.from('companies')
.select(`
id,
name,
slug,
company_type,
person_type,
headquarters_location,
founded_year,
logo_url
`)
.eq('slug', slug)
.maybeSingle();
if (error) throw error;
return data;
},
enabled: enabled && !!slug,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 15 * 60 * 1000, // 15 minutes
});
}

View File

@@ -0,0 +1,39 @@
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/lib/supabaseClient';
import { queryKeys } from '@/lib/queryKeys';
/**
* Hook to fetch park preview data for hover cards
*/
export function useParkPreview(slug: string | undefined, enabled = true) {
return useQuery({
queryKey: queryKeys.parks.detail(slug || ''),
queryFn: async () => {
if (!slug) throw new Error('Slug is required');
const { data, error } = await supabase
.from('parks')
.select(`
id,
name,
slug,
park_type,
status,
card_image_url,
ride_count,
coaster_count,
average_rating,
review_count,
location:locations(city, state_province, country)
`)
.eq('slug', slug)
.maybeSingle();
if (error) throw error;
return data;
},
enabled: enabled && !!slug,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 15 * 60 * 1000, // 15 minutes
});
}