more filling out of game page
This commit is contained in:
@@ -33,6 +33,8 @@ export interface DetailedGame extends Game {
|
||||
favorite?: boolean;
|
||||
manualUrl?: string;
|
||||
platformId?: number;
|
||||
videoUrl?: string; // Direct video link
|
||||
youtubeId?: string; // YouTube ID for embed
|
||||
}
|
||||
|
||||
export interface RommCollection {
|
||||
@@ -309,7 +311,6 @@ export const rommApiClient = {
|
||||
genres: getAll('genres').map(sanitize).filter(Boolean),
|
||||
franchises: getAll('franchises').map(sanitize).filter(Boolean),
|
||||
releaseDate: formatDate(json.release_date || getFirst('first_release_date') || getFirst('release_date')),
|
||||
screenshots: (json.screenshots || []).map((s: any) => s.url ? getFullImageUrl(s.url) || '' : ''),
|
||||
fsName: json.fs_name,
|
||||
regions: regions.length > 0 ? regions : ['Global'],
|
||||
players: (() => {
|
||||
@@ -338,6 +339,13 @@ export const rommApiClient = {
|
||||
favorite: (json.user_collections || json.rom_collections || []).some((c: any) => c.is_favorite || c.name === 'Favorites'),
|
||||
manualUrl: getFullImageUrl(json.url_manual),
|
||||
platformId: json.platform_id,
|
||||
videoUrl: getFullImageUrl(json.url_video || json.ss_metadata?.video_url),
|
||||
youtubeId: json.youtube_video_id || json.igdb_metadata?.youtube_video_id || json.launchbox_metadata?.youtube_video_id,
|
||||
screenshots: Array.from(new Set([
|
||||
...(json.merged_screenshots || []).map((s: string) => getFullImageUrl(s)),
|
||||
...(json.screenshots || []).map((s: any) => s.url ? getFullImageUrl(s.url) || '' : ''),
|
||||
...(getFirst('screenshots') || [])
|
||||
])).filter(Boolean) as string[],
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ export const GamesPage = () => {
|
||||
const [playingGameId, setPlayingGameId] = useState<string | null>(null);
|
||||
const [isCollectionModalOpen, setIsCollectionModalOpen] = useState(false);
|
||||
const [isManualModalOpen, setIsManualModalOpen] = useState(false);
|
||||
const [activeMediaIndex, setActiveMediaIndex] = useState(0);
|
||||
const [activeZone, setActiveZone] = useState<'platforms' | 'games' | 'alphabet' | 'details' | null>(null);
|
||||
const detailTimeoutRef = React.useRef<any>(null);
|
||||
|
||||
@@ -308,6 +309,29 @@ export const GamesPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Consolidate media for Galleria
|
||||
const mediaItems = React.useMemo(() => {
|
||||
if (!detailsQuery.data) return [];
|
||||
const items: { type: 'video' | 'image', url: string, youtubeId?: string }[] = [];
|
||||
|
||||
if (detailsQuery.data.youtubeId) {
|
||||
items.push({ type: 'video', url: '', youtubeId: detailsQuery.data.youtubeId });
|
||||
} else if (detailsQuery.data.videoUrl) {
|
||||
items.push({ type: 'video', url: detailsQuery.data.videoUrl });
|
||||
}
|
||||
|
||||
if (detailsQuery.data.screenshots) {
|
||||
detailsQuery.data.screenshots.forEach(s => {
|
||||
items.push({ type: 'image', url: s });
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}, [detailsQuery.data]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveMediaIndex(0);
|
||||
}, [selectedGameId]);
|
||||
|
||||
const updateFocusFromScroll = (container: HTMLElement) => {
|
||||
const rect = container.getBoundingClientRect();
|
||||
const centerX = rect.left + rect.width / 2;
|
||||
@@ -660,6 +684,77 @@ export const GamesPage = () => {
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Media Galleria Container */}
|
||||
{mediaItems.length > 0 && (
|
||||
<div className="mt-12 grid grid-cols-12 gap-8">
|
||||
<div className="col-span-6 bg-white/5 rounded-[12px] p-5 border border-white/5 flex flex-col shadow-2xl">
|
||||
{/* Active Media Slot */}
|
||||
<div className="aspect-video w-full rounded-[10px] bg-black/40 border border-white/10 overflow-hidden relative mb-5 group">
|
||||
{mediaItems[activeMediaIndex].type === 'video' ? (
|
||||
mediaItems[activeMediaIndex].youtubeId ? (
|
||||
<iframe
|
||||
src={`https://www.youtube.com/embed/${mediaItems[activeMediaIndex].youtubeId}?autoplay=0&controls=1&rel=0&modestbranding=1`}
|
||||
className="w-full h-full"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
) : (
|
||||
<video
|
||||
key={mediaItems[activeMediaIndex].url}
|
||||
src={mediaItems[activeMediaIndex].url}
|
||||
controls
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<img
|
||||
src={mediaItems[activeMediaIndex].url}
|
||||
className="w-full h-full object-cover animate-fade-in"
|
||||
alt="Gallery Preview"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Thumbnail Row */}
|
||||
<div className="flex gap-3 overflow-x-auto pb-2 scrollbar-hide">
|
||||
{mediaItems.map((item, idx) => (
|
||||
<FocusableItem
|
||||
key={idx}
|
||||
onFocus={() => {
|
||||
if (mode === 'gamepad') setActiveZone('details');
|
||||
setActiveMediaIndex(idx);
|
||||
}}
|
||||
onClick={() => setActiveMediaIndex(idx)}
|
||||
className="shrink-0"
|
||||
focusKey={`THUMB_${idx}`}
|
||||
>
|
||||
{(focused) => (
|
||||
<div className={`w-[124px] aspect-video rounded-[6px] border-2 transition-all duration-300 overflow-hidden relative ${focused || activeMediaIndex === idx ? 'border-[#2563eb] scale-105 z-10' : 'border-white/10 opacity-40 grayscale hover:opacity-100 hover:grayscale-0'}`}>
|
||||
{item.type === 'video' ? (
|
||||
<div className="w-full h-full bg-black/60 flex items-center justify-center">
|
||||
<span className="material-symbols-outlined text-[#2563eb] text-3xl filled">play_circle</span>
|
||||
</div>
|
||||
) : (
|
||||
<img src={item.url} className="w-full h-full object-cover" alt="" />
|
||||
)}
|
||||
{activeMediaIndex === idx && (
|
||||
<div className="absolute inset-0 bg-[#2563eb]/20 pointer-events-none"></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</FocusableItem>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Placeholder for the "something else" mentioned by user */}
|
||||
<div className="col-span-6 bg-white/5 rounded-[12px] p-5 border border-white/5 border-dashed flex items-center justify-center opacity-20">
|
||||
<div className="text-center geist-mono uppercase tracking-[0.3em] text-[10px]">
|
||||
Future Content Zone
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : selectedGameId ? (
|
||||
<div className="h-full flex items-center justify-center">
|
||||
|
||||
Reference in New Issue
Block a user