Expand IGDB data: collections, game modes, themes, perspectives, videos, websites, age ratings, similar games; add backfill command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
0eab3e8dbf
commit
2a724c0ae2
@@ -236,7 +236,7 @@
|
||||
|
||||
{{-- Companies --}}
|
||||
@if($game->companies->isNotEmpty())
|
||||
<div class="text-sm text-slate-500 space-y-1">
|
||||
<div class="text-sm text-slate-500 space-y-1 mb-4">
|
||||
@php
|
||||
$developers = $game->companies->where('pivot.role', 'developer');
|
||||
$publishers = $game->companies->where('pivot.role', 'publisher');
|
||||
@@ -250,6 +250,87 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Extended metadata --}}
|
||||
<div class="text-sm text-slate-400 space-y-2">
|
||||
@if($game->collection)
|
||||
<div class="flex gap-2">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Series / Collection</span>
|
||||
<span class="text-slate-300">{{ $game->collection->name }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($game->gameModes->isNotEmpty())
|
||||
<div class="flex gap-2">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Game Modes</span>
|
||||
<span class="text-slate-300">{{ $game->gameModes->pluck('name')->join(', ') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($game->themes->isNotEmpty())
|
||||
<div class="flex gap-2">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Themes</span>
|
||||
<span class="text-slate-300">{{ $game->themes->pluck('name')->join(', ') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($game->playerPerspectives->isNotEmpty())
|
||||
<div class="flex gap-2">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Perspective</span>
|
||||
<span class="text-slate-300">{{ $game->playerPerspectives->pluck('name')->join(', ') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($game->aggregated_rating)
|
||||
<div class="flex gap-2 items-center">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Critics Score</span>
|
||||
<span class="px-2 py-0.5 rounded text-xs font-bold
|
||||
@if($game->aggregated_rating >= 75) bg-green-900/50 text-green-300
|
||||
@elseif($game->aggregated_rating >= 50) bg-yellow-900/50 text-yellow-300
|
||||
@else bg-red-900/50 text-red-300
|
||||
@endif">
|
||||
{{ round($game->aggregated_rating) }}/100
|
||||
</span>
|
||||
@if($game->aggregated_rating_count)
|
||||
<span class="text-slate-600 text-xs">({{ $game->aggregated_rating_count }} {{ Str::plural('review', $game->aggregated_rating_count) }})</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@if($game->age_rating_pegi || $game->age_rating_esrb)
|
||||
<div class="flex gap-2 items-center">
|
||||
<span class="text-slate-500 w-36 flex-shrink-0">Age Ratings</span>
|
||||
<div class="flex gap-2">
|
||||
@if($game->age_rating_pegi)
|
||||
<span class="px-2 py-0.5 bg-[#16161d] border border-white/10 rounded text-xs font-bold text-slate-300">PEGI {{ $game->age_rating_pegi }}</span>
|
||||
@endif
|
||||
@if($game->age_rating_esrb)
|
||||
<span class="px-2 py-0.5 bg-[#16161d] border border-white/10 rounded text-xs font-bold text-slate-300">ESRB {{ $game->age_rating_esrb }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Websites --}}
|
||||
@php
|
||||
$importantCategories = [1, 13, 17, 16];
|
||||
$featuredSites = $game->websites->whereIn('category', $importantCategories)->sortBy(fn($w) => array_search($w->category, $importantCategories));
|
||||
@endphp
|
||||
@if($featuredSites->isNotEmpty())
|
||||
<div class="flex flex-wrap gap-2 mt-4">
|
||||
@foreach($featuredSites as $site)
|
||||
<a href="{{ $site->url }}" target="_blank" rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-[#16161d] border border-white/10 hover:border-purple-500/50 rounded-lg text-xs text-slate-300 hover:text-white transition-all">
|
||||
@if($site->category === 13)
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor"><path d="M11.979 0C5.678 0 .511 4.86.022 11.037l6.432 2.658c.545-.371 1.203-.59 1.912-.59.063 0 .125.004.187.006l2.861-4.142V8.91c0-2.495 2.028-4.524 4.524-4.524 2.494 0 4.524 2.029 4.524 4.524s-2.03 4.525-4.524 4.525h-.105l-4.076 2.911c0 .052.004.105.004.159 0 1.875-1.515 3.396-3.39 3.396-1.635 0-3.016-1.173-3.331-2.727L.436 15.27C1.862 20.307 6.486 24 11.979 24c6.627 0 11.999-5.373 11.999-12S18.606 0 11.979 0zM7.54 18.21l-1.473-.61c.262.543.714.999 1.314 1.25 1.297.539 2.793-.076 3.332-1.375.263-.63.264-1.319.005-1.949s-.75-1.121-1.377-1.383c-.624-.26-1.29-.249-1.878-.03l1.523.63c.956.4 1.409 1.5 1.009 2.455-.397.957-1.497 1.41-2.455 1.012H7.54zm11.415-9.303c0-1.662-1.353-3.015-3.015-3.015-1.665 0-3.015 1.353-3.015 3.015 0 1.665 1.35 3.015 3.015 3.015 1.663 0 3.015-1.35 3.015-3.015zm-5.273-.005c0-1.252 1.013-2.266 2.265-2.266 1.249 0 2.266 1.014 2.266 2.266 0 1.251-1.017 2.265-2.266 2.265-1.252 0-2.265-1.014-2.265-2.265z"/></svg>
|
||||
@elseif($site->category === 17)
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12s5.37 12 12 12 12-5.37 12-12S18.63 0 12 0zm5.61 17.26c-.2.2-.52.2-.72 0l-4.89-4.89-4.89 4.89c-.2.2-.52.2-.72 0-.2-.2-.2-.52 0-.72l4.89-4.89-4.89-4.89c-.2-.2-.2-.52 0-.72.2-.2.52-.2.72 0l4.89 4.89 4.89-4.89c.2-.2.52-.2.72 0 .2.2.2.52 0 .72l-4.89 4.89 4.89 4.89c.2.2.2.52 0 .72z"/></svg>
|
||||
@elseif($site->category === 16)
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 6.5C21 4.6 19.5 3 17.5 3c-1.9 0-3.5 1.6-3.5 3.5C14 8.4 15.6 10 17.5 10c1.9 0 3.5-1.5 3.5-3.5zM6.5 3C4.6 3 3 4.6 3 6.5S4.6 10 6.5 10 10 8.4 10 6.5 8.4 3 6.5 3zM17.5 14c-1.9 0-3.5 1.6-3.5 3.5S15.6 21 17.5 21c1.9 0 3.5-1.5 3.5-3.5S19.4 14 17.5 14zm-11 0C4.6 14 3 15.6 3 17.5S4.6 21 6.5 21 10 19.4 10 17.5 8.4 14 6.5 14z"/></svg>
|
||||
@else
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
||||
@endif
|
||||
{{ $site->label }}
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -261,6 +342,52 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Storyline (only if different from summary) --}}
|
||||
@if($game->storyline && $game->storyline !== $game->summary)
|
||||
<div class="mt-8">
|
||||
<h2 class="text-lg font-semibold text-white mb-3">Storyline</h2>
|
||||
<p class="text-slate-400 leading-relaxed max-w-3xl">{{ $game->storyline }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Trailers --}}
|
||||
@if($game->videos->isNotEmpty())
|
||||
<div class="mt-10 pt-8 border-t border-white/5"
|
||||
x-data="{
|
||||
activeVideo: '{{ $game->videos->first()->video_id }}',
|
||||
activeName: {{ json_encode($game->videos->first()->name ?? 'Trailer') }},
|
||||
}">
|
||||
<h2 class="text-lg font-semibold text-white mb-4">Videos</h2>
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="aspect-video rounded-xl overflow-hidden bg-black">
|
||||
<iframe
|
||||
:src="'https://www.youtube.com/embed/' + activeVideo + '?rel=0'"
|
||||
class="w-full h-full"
|
||||
loading="lazy"
|
||||
allowfullscreen
|
||||
title="Game video"
|
||||
></iframe>
|
||||
</div>
|
||||
<p class="text-sm text-slate-500 mt-2" x-text="activeName"></p>
|
||||
</div>
|
||||
@if($game->videos->count() > 1)
|
||||
<div class="flex lg:flex-col gap-2 overflow-x-auto lg:overflow-y-auto lg:max-h-72 lg:w-48 flex-shrink-0">
|
||||
@foreach($game->videos as $video)
|
||||
<button @click="activeVideo = '{{ $video->video_id }}'; activeName = {{ json_encode($video->name ?? 'Video') }}"
|
||||
class="flex-shrink-0 lg:flex-shrink rounded-lg overflow-hidden border-2 transition-all w-32 lg:w-full aspect-video bg-black"
|
||||
:class="activeVideo === '{{ $video->video_id }}' ? 'border-purple-500' : 'border-transparent hover:border-white/20'">
|
||||
<img src="https://img.youtube.com/vi/{{ $video->video_id }}/mqdefault.jpg"
|
||||
alt="{{ $video->name ?? 'Video' }}"
|
||||
class="w-full h-full object-cover">
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Screenshots --}}
|
||||
@if($game->screenshots->isNotEmpty())
|
||||
<div class="mt-10 pt-8 border-t border-white/5"
|
||||
@@ -554,7 +681,13 @@
|
||||
|
||||
@if($similarGames->isNotEmpty())
|
||||
<div class="mt-10 pt-8 border-t border-white/5">
|
||||
<h2 class="text-lg font-semibold text-white mb-4">You Might Also Like</h2>
|
||||
<h2 class="text-lg font-semibold text-white mb-4">
|
||||
@if($game->similarGames->isNotEmpty())
|
||||
Similar Games
|
||||
@else
|
||||
You Might Also Like
|
||||
@endif
|
||||
</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
@foreach($similarGames as $similar)
|
||||
<x-game-card :game="$similar" />
|
||||
|
||||
Reference in New Issue
Block a user