feat: Add streamers to champion show view

- Added loading of streamers data in the champion show view.
- Updated ChampionController to load streamers for display.
This commit is contained in:
Rico van Zelst
2024-03-23 02:48:08 +01:00
parent b46128ec26
commit e6dcfacb31
10 changed files with 127 additions and 126 deletions

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@ yarn-error.log
/.vscode /.vscode
_ide_helper.php _ide_helper.php
.phpstorm.meta.php .phpstorm.meta.php
_ide_helper_models.php

View File

@@ -24,22 +24,6 @@ class ChampionController extends Controller
return view('champions.index', ['champions' => $champions, 'roles' => $roles]); return view('champions.index', ['champions' => $champions, 'roles' => $roles]);
} }
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(StoreChampionRequest $request)
{
//
}
/** /**
* Display the specified resource. * Display the specified resource.
*/ */
@@ -47,41 +31,21 @@ class ChampionController extends Controller
{ {
$threeDaysInSeconds = 60 * 60 * 24 * 3; $threeDaysInSeconds = 60 * 60 * 24 * 3;
$sixMonthsInSeconds = 60 * 60 * 24 * 30 * 6; $sixMonthsInSeconds = 60 * 60 * 24 * 30 * 6;
$tenMinutesInSeconds = 60 * 10;
$champion = Cache::remember('championShowCache'.$champion->slug, $threeDaysInSeconds, static fn () => $champion->load('skins', 'lanes')); $champion = Cache::remember('championShowCache' . $champion->slug, $threeDaysInSeconds, static fn () => $champion->load('streamers', 'skins', 'lanes'));
//$streamers = Cache::remember('championStreamersCache' . $champion->slug, $tenMinutesInSeconds, static fn () => $champion->streamers);
$streamers = $champion->load('streamers')->streamers;
$splashColor = Cache::remember( $splashColor = Cache::remember(
'championSplashColorCache'.$champion->slug, 'championSplashColorCache' . $champion->slug,
$sixMonthsInSeconds, $sixMonthsInSeconds,
static fn () => getAverageColorFromImageUrl($champion->getChampionImageAttribute()) static fn () => getAverageColorFromImageUrl($champion->getChampionImageAttribute())
); );
$champion->splash_color = $splashColor; $champion->splash_color = $splashColor;
return view('champions.show', ['champion' => $champion]); return view('champions.show', ['champion' => $champion, 'streamers' => $streamers]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Champion $champion)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateChampionRequest $request, Champion $champion)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Champion $champion)
{
//
} }
} }

View File

@@ -14,7 +14,7 @@ class StreamerPanelController extends Controller
public function index() public function index()
{ {
return view('streamerpanel.index', [ return view('streamerpanel.index', [
'streamers' => Streamer::all(), 'streamers' => Streamer::with('champion')->get(),
]); ]);
} }
@@ -33,8 +33,7 @@ class StreamerPanelController extends Controller
*/ */
public function store(Request $request) public function store(Request $request)
{ {
$request->validate([ $request->validate(['champion_id' => 'required|exists:champions,champion_id',
'champion_id' => 'required|exists:champions,id',
'platform' => 'required|in:twitch,youtube,kick,douyu,huya', 'platform' => 'required|in:twitch,youtube,kick,douyu,huya',
'username' => 'required|string', 'username' => 'required|string',
'displayname' => 'required|string', 'displayname' => 'required|string',

View File

@@ -94,6 +94,11 @@ class Champion extends Model
return $this->hasOne(ChampionRoles::class, 'champion_id', 'champion_id'); return $this->hasOne(ChampionRoles::class, 'champion_id', 'champion_id');
} }
public function streamers()
{
return $this->hasMany(Streamer::class, 'champion_id', 'champion_id');
}
public function getChampionImageAttribute($centered = true): string public function getChampionImageAttribute($centered = true): string
{ {
$url = 'https://cdn.communitydragon.org/latest/champion/'.$this->champion_id.'/splash-art'; $url = 'https://cdn.communitydragon.org/latest/champion/'.$this->champion_id.'/splash-art';

View File

@@ -4,6 +4,8 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Champion;
class Streamer extends Model class Streamer extends Model
{ {
@@ -11,10 +13,6 @@ class Streamer extends Model
protected $fillable = ['champion_id', 'platform', 'username', 'displayname']; protected $fillable = ['champion_id', 'platform', 'username', 'displayname'];
public function champion()
{
return $this->belongsTo(Champion::class);
}
public function getPlatformAttribute($value): string public function getPlatformAttribute($value): string
{ {
@@ -39,4 +37,9 @@ class Streamer extends Model
'Huya' => "https://www.huya.com/{$this->username}", 'Huya' => "https://www.huya.com/{$this->username}",
}; };
} }
public function champion(): BelongsTo
{
return $this->belongsTo(Champion::class, 'champion_id', 'champion_id');
}
} }

View File

@@ -13,11 +13,16 @@ return new class extends Migration
{ {
Schema::create('streamers', function (Blueprint $table) { Schema::create('streamers', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('champion_id')->constrained(); $table->integer('champion_id');
$table->enum('platform', ['twitch', 'youtube', 'kick', 'douyu', 'huya']); $table->enum('platform', ['twitch', 'youtube', 'kick', 'douyu', 'huya']);
$table->string('username'); $table->string('username');
$table->string('displayname'); $table->string('displayname');
$table->foreign('champion_id')->references('champion_id')->on('champions')->onDelete('cascade');
$table->timestamps(); $table->timestamps();
}); });
} }

View File

@@ -5,7 +5,7 @@
about ' . $champion->name . ', ' . $champion->title . '. ' . substr($champion->lore, 0, 50) . '...') about ' . $champion->name . ', ' . $champion->title . '. ' . substr($champion->lore, 0, 50) . '...')
@section('content') @section('content')
<x-champions.grid_info :champion="$champion"/> <x-champions.grid_info :champion="$champion" :streamers="$streamers"/>
@endsection @endsection
@push('bottom_scripts') @push('bottom_scripts')

View File

@@ -5,125 +5,136 @@
CHAMPION DETAILS</h3> CHAMPION DETAILS</h3>
<h1 <h1
class="text-3xl font-bold text-center text-transparent uppercase sm:text-4xl bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text"> class="text-3xl font-bold text-center text-transparent uppercase sm:text-4xl bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text">
{{$champion->name}}</h1> {{ $champion->name }}</h1>
<h2 <h2
class="text-sm md:text-lg font-bold text-center text-transparent uppercase bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text"> class="text-sm font-bold text-center text-transparent uppercase md:text-lg bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text">
{{$champion->title}}</h2> {{ $champion->title }}</h2>
<div class="container mx-auto p-4 flex items-center justify-center mt-3"> <div class="container flex items-center justify-center p-4 mx-auto mt-3">
<div class="w-screen grid grid-cols-1 md-grid-cols-2 lg:grid-cols-3 gap-5"> <div class="grid w-screen grid-cols-1 gap-5 md-grid-cols-2 lg:grid-cols-3">
<div <div
class="relative rounded-2xl bg-stone-800/40 border border-neutral-300/5 shadow-sm shadow-stone-800/80 lg:col-span-2"> class="relative border shadow-sm rounded-2xl bg-stone-800/40 border-neutral-300/5 shadow-stone-800/80 lg:col-span-2">
<div class="aspect-w-16 aspect-h-9 glow-shadow absolute inset-0 rounded-2xl" <div class="absolute inset-0 aspect-w-16 aspect-h-9 glow-shadow rounded-2xl"
style="--splash-color: {{$champion->splash_color}}"></div> style="--splash-color: {{ $champion->splash_color }}"></div>
<div class="aspect-w-16 aspect-h-9 overflow-hidden rounded-2xl relative"> <div class="relative overflow-hidden aspect-w-16 aspect-h-9 rounded-2xl">
<img <img src="//wsrv.nl/?url={{ $champion->getChampionImageAttribute(false) }}&w=880&output=webp&q=85&il"
src="//wsrv.nl/?url={{ $champion->getChampionImageAttribute(false) }}&w=880&output=webp&q=85&il" alt="{{ $champion->name }} Splash Art"
alt="{{$champion->name}} Splash Art" class="z-10 object-cover w-full h-full transition-transform duration-700 transform scale-100 hover:scale-105">
class="w-full h-full object-cover transform scale-100 transition-transform duration-700 hover:scale-105 z-10"
>
</div> </div>
</div> </div>
<div <div class="transition-all duration-700 border shadow-md rounded-2xl border-3 border-white/10 lg:col-start-3"
class="rounded-2xl border border-3 border-white/10 lg:col-start-3 shadow-md transition-all duration-700" style="--tw-shadow-color:{{ $champion->splash_color }}; --tw-shadow: var(--tw-shadow-colored); background-color: {{ $champion->splash_color }};">
style="--tw-shadow-color:{{$champion->splash_color}}; --tw-shadow: var(--tw-shadow-colored); background-color: {{$champion->splash_color}};">
<h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-3.5 shadow-sm"> <h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-3.5 shadow-sm">
{{$champion->name}} Information</h4> {{ $champion->name }} Information</h4>
<ul class="ml-7"> <ul class="ml-7">
<li class="text-neutral-100 hyphens-auto text-base font-medium leading-loose mt-8" lang="en"> <li class="mt-8 text-base font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Full Title:</span> {{$champion->name}}, {{$champion->title}}. <span class="font-bold">Full Title:</span> {{ $champion->name }}, {{ $champion->title }}.
</li> </li>
<li class="text-neutral-100 hyphens-auto text-base font-medium leading-loose" lang="en"> <li class="text-base font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Popular Positions:</span> @foreach($champion->lanes->roles as $lane) <span class="font-bold">Popular Positions:</span>
<span @foreach ($champion->lanes->roles as $lane)
class="inline-block lowercase capitalize-first">{{$lane}} @svg(getRoleIconSvg($lane), 'w-5 h-5 inline-block') <span class="inline-block lowercase capitalize-first">{{ $lane }} @svg(getRoleIconSvg($lane), 'w-5 h-5 inline-block')
@if(!$loop->last) @if (!$loop->last)
- -
@endif</span> @endif
</span>
@endforeach @endforeach
</li> </li>
<li class="text-neutral-100 hyphens-auto text-base font-medium leading-loose items-center" <li class="items-center text-base font-medium leading-loose text-neutral-100 hyphens-auto"
lang="en"> lang="en">
<span class="font-bold">Blue Essence Cost:</span> <span class="font-bold">Blue Essence Cost:</span>
<x-icon-lcu-be-svg class="inline-block w-4"/> {{$champion->price_be}} BE <x-icon-lcu-be-svg class="inline-block w-4" /> {{ $champion->price_be }} BE
</li> </li>
<li class="text-neutral-100 hyphens-auto text-medium font-medium leading-loose items-center" <li class="items-center font-medium leading-loose text-neutral-100 hyphens-auto text-medium"
lang="en"> lang="en">
<span class="font-bold">Riot Points Cost:</span> <span class="font-bold">Riot Points Cost:</span>
<x-icon-RiotPoints class="inline-block w-4"/> {{$champion->price_rp}} RP <x-icon-RiotPoints class="inline-block w-4" /> {{ $champion->price_rp }} RP
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Roles:</span> @foreach($champion->roles as $role) <span class="font-bold">Roles:</span>
<span @foreach ($champion->roles as $role)
class="inline-block lowercase capitalize-first">{{$role}} <span class="inline-block lowercase capitalize-first">{{ $role }}
@if(!$loop->last) @if (!$loop->last)
- -
@endif</span> @endif
</span>
@endforeach @endforeach
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Attack Type:</span> <span <span class="font-bold">Attack Type:</span> <span
class="inline-block lowercase capitalize-first">{{$champion->attack_type}}</span> class="inline-block lowercase capitalize-first">{{ $champion->attack_type }}</span>
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Damage Type:</span> {{$champion->adaptive_type}} <span class="font-bold">Damage Type:</span> {{ $champion->adaptive_type }}
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Resource Type:</span> {{$champion->resource_type}} <span class="font-bold">Resource Type:</span> {{ $champion->resource_type }}
</li> </li>
<li class="text-neutral-100 hyphens-auto text-base font-medium leading-loose" lang="en"> <li class="text-base font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Champion ID:</span> <span <span class="font-bold">Champion ID:</span> <span
class="font-mono font-medium">{{$champion->champion_id}}</span> class="font-mono font-medium">{{ $champion->champion_id }}</span>
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Release Date:</span> {{$champion->release_date}} <span class="font-bold">Release Date:</span> {{ $champion->release_date }}
</li> </li>
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en"> <li class="font-medium leading-loose text-neutral-100 hyphens-auto" lang="en">
<span class="font-bold">Release Patch:</span> Patch {{$champion->release_patch}} <span class="font-bold">Release Patch:</span> Patch {{ $champion->release_patch }}
</li> </li>
</ul> </ul>
</div> </div>
<div class="rounded-2xl border border-3 border-white/10 shadow-md shadow-stone-800/80 hover:shadow-orange-500/20 transition-all duration-700" <div class="transition-all duration-700 border shadow-md rounded-2xl border-3 border-white/10 shadow-stone-800/80 hover:shadow-orange-500/20"
style="--tw-shadow-color:{{$champion->splash_color}}; --tw-shadow: var(--tw-shadow-colored); background-color: {{$champion->splash_color}};"> style="--tw-shadow-color:{{ $champion->splash_color }}; --tw-shadow: var(--tw-shadow-colored); background-color: {{ $champion->splash_color }};">
<div class="p-4"> <div class="p-4">
<h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm"> <h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm">
{{$champion->name}} Lore</h4> {{ $champion->name }} Streamers</h4>
<p class="text-neutral-100 hyphens-auto text-base mt-2.5 leading-loose" lang="en"> <p class="text-neutral-100/75 hyphens-auto mt-2.5 leading-loose text-center text-sm" lang="en">
{{$champion->lore}} A list of streamers who play {{ $champion->name }} and are atleast Diamond 2 or higher.
</p> </p>
<div class="grid grid-cols-1 gap-4 mt-2.5 lg:grid-cols-2">
@foreach ($streamers as $streamer)
<div class="flex justify-center items -center">
<div class="flex flex-col items-center justify-center">
<a href="{{ $streamer->streamer_url }}" target="_blank" rel="noopener noreferrer"
class="text-center text-neutral-100 text-sm mt-1.5 items-center">
{{ $streamer->displayname }}
</a>
</div>
</div>
@endforeach
</div> </div>
</div> </div>
<div </div>
class="rounded-2xl border border-3 border-white/10 shadow-md shadow-stone-800/80 lg:col-span-2 hover:shadow-orange-500/20 transition-all duration-700" <div class="transition-all duration-700 border shadow-md rounded-2xl border-3 border-white/10 shadow-stone-800/80 lg:col-span-2 hover:shadow-orange-500/20"
style="--tw-shadow-color:{{$champion->splash_color}}; --tw-shadow: var(--tw-shadow-colored); background-color: {{$champion->splash_color}};"> style="--tw-shadow-color:{{ $champion->splash_color }}; --tw-shadow: var(--tw-shadow-colored); background-color: {{ $champion->splash_color }};">
<div class="p-4"> <div class="p-4">
<h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm"> <h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm">
{{$champion->name}} Skins ({{count($champion->skins)}}) </h4> {{ $champion->name }} Skins ({{ count($champion->skins) }}) </h4>
<div id="skinsElement" class="overflow-x-scroll mt-2.5"> <div id="skinsElement" class="overflow-x-scroll mt-2.5">
<div class="grid grid-flow-col grid-rows-2 w-max gap-4 mb-2.5"> <div class="grid grid-flow-col grid-rows-2 w-max gap-4 mb-2.5">
@foreach($champion->skins as $key => $skin) @foreach ($champion->skins as $key => $skin)
<div class="group flex flex-col"> <div class="flex flex-col group">
<a href="/skin/{{$skin->slug}}"> <a href="/skin/{{ $skin->slug }}">
<img <img src="//wsrv.nl/?url={{ $skin->getSkinImageAttribute() }}&w=450&output=webp&q=70&il"
src="//wsrv.nl/?url={{ $skin->getSkinImageAttribute() }}&w=450&output=webp&q=70&il" alt="{{ $champion->name }} {{ $skin->name }} Splash Art"
alt="{{$champion->name}} {{$skin->name}} Splash Art" @if ($key < 6) loading="eager" @else loading="lazy" @endif
@if($key < 6) loading="eager" @else loading="lazy" @endif
class="inline-block h-36 object-cover rounded-2xl shadow-md border border-3 border-white/10 hover:shadow-orange-500/20 transition-all duration-700 mr-2.5"> class="inline-block h-36 object-cover rounded-2xl shadow-md border border-3 border-white/10 hover:shadow-orange-500/20 transition-all duration-700 mr-2.5">
</a> </a>
<div> <div>
<p class="align-bottom text-center text-neutral-100 text-sm mt-1.5 items-center"> <p
<a href="/skin/{{$skin->slug}}" class="align-bottom text-center text-neutral-100 text-sm mt-1.5 items-center">
<a href="/skin/{{ $skin->slug }}"
class="hover:text-orange-400 group-hover:text-orange-400"> class="hover:text-orange-400 group-hover:text-orange-400">
{{$skin->skin_name}} {{ $skin->skin_name }}
<x-iconsax-bul-arrow-right class="inline-block w-5"/> <x-iconsax-bul-arrow-right class="inline-block w-5" />
</a> </a>
</p> </p>
</div> </div>
@@ -133,6 +144,17 @@
</div> </div>
</div> </div>
</div> </div>
<div class="transition-all duration-700 border shadow-md lg:col-span-3 rounded-2xl border-3 border-white/10 shadow-stone-800/80 hover:shadow-orange-500/20"
style="--tw-shadow-color:{{ $champion->splash_color }}; --tw-shadow: var(--tw-shadow-colored); background-color: {{ $champion->splash_color }};">
<div class="p-4">
<h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm">
{{ $champion->name }} Lore</h4>
<p class="text-neutral-100 hyphens-auto text-base mt-2.5 leading-loose w-9/12 mx-auto"
lang="en">
{{ $champion->lore }}
</p>
</div>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@@ -3,9 +3,10 @@
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
<div class="flex flex-col space-y-2"> <div class="flex flex-col space-y-2">
<label for="champion_id" class="text-lg font-semibold text-orange-400">Champion</label> <label for="champion_id" class="text-lg font-semibold text-orange-400">Champion</label>
<select name="champion_id" id="champion_id" class="w-full p-2 text-white rounded-md bg-stone-800"> <select name="champion_id" required id="champion_id" class="w-full p-2 text-white rounded-md bg-stone-800">
<option value="">Select a champion</option>
@foreach ($champions as $champion) @foreach ($champions as $champion)
<option value="{{ $champion->id }}">{{ $champion->name }}</option> <option value="{{ $champion->champion_id }}">{{ $champion->name }}</option>
@endforeach @endforeach
</select> </select>
</div> </div>
@@ -21,7 +22,8 @@
</div> </div>
<div class="flex flex-col space-y-2"> <div class="flex flex-col space-y-2">
<label for="username" class="text-lg font-semibold text-orange-400">Username</label> <label for="username" class="text-lg font-semibold text-orange-400">Username</label>
<input type="text" name="username" id="username" class="w-full p-2 text-white rounded-md bg-stone-800" /> <input type="text" name="username" id="username"
class="w-full p-2 text-white rounded-md bg-stone-800" />
</div> </div>
<div class="flex flex-col space-y-2"> <div class="flex flex-col space-y-2">
<label for="displayname" class="text-lg font-semibold text-orange-400">Display Name</label> <label for="displayname" class="text-lg font-semibold text-orange-400">Display Name</label>

View File

@@ -2,7 +2,6 @@
<script src="https://cdn.jsdelivr.net/npm/gridjs/dist/gridjs.umd.js"></script> <script src="https://cdn.jsdelivr.net/npm/gridjs/dist/gridjs.umd.js"></script>
<link href="https://cdn.jsdelivr.net/npm/gridjs/dist/theme/mermaid.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/gridjs/dist/theme/mermaid.min.css" rel="stylesheet" />
@endpush @endpush
<div class="w-10/12 mx-auto"> <div class="w-10/12 mx-auto">
<div id="streamers-wrapper"></div> <div id="streamers-wrapper"></div>
</div> </div>