mirror of
https://github.com/rico-vz/HeimerdingerLoL.git
synced 2025-12-06 10:10:48 +01:00
Merge pull request #168 from rico-vz/streamers
Add Streamers functionality
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,3 +19,5 @@ yarn-error.log
|
||||
/.vscode
|
||||
_ide_helper.php
|
||||
.phpstorm.meta.php
|
||||
|
||||
_ide_helper_models.php
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\StoreChampionRequest;
|
||||
use App\Http\Requests\UpdateChampionRequest;
|
||||
use App\Models\Champion;
|
||||
use App\Models\ChampionRoles;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
@@ -24,22 +22,6 @@ class ChampionController extends Controller
|
||||
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.
|
||||
*/
|
||||
@@ -48,7 +30,9 @@ class ChampionController extends Controller
|
||||
$threeDaysInSeconds = 60 * 60 * 24 * 3;
|
||||
$sixMonthsInSeconds = 60 * 60 * 24 * 30 * 6;
|
||||
|
||||
$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 = $champion->load('streamers')->streamers;
|
||||
|
||||
$splashColor = Cache::remember(
|
||||
'championSplashColorCache'.$champion->slug,
|
||||
@@ -58,30 +42,6 @@ class ChampionController extends Controller
|
||||
|
||||
$champion->splash_color = $splashColor;
|
||||
|
||||
return view('champions.show', ['champion' => $champion]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
return view('champions.show', ['champion' => $champion, 'streamers' => $streamers]);
|
||||
}
|
||||
}
|
||||
|
||||
36
app/Http/Controllers/StreamerController.php
Normal file
36
app/Http/Controllers/StreamerController.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Streamer;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class StreamerController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Streamer $streamer)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* API: JSON response of all streamers.
|
||||
* Data is cached for 12 hours.
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
$streamers = Cache::remember('streamersListAllAPICache', 60 * 60 * 12, static fn () => Streamer::orderBy('champion_id')->get());
|
||||
|
||||
return response()->json($streamers);
|
||||
}
|
||||
}
|
||||
91
app/Http/Controllers/StreamerPanelController.php
Normal file
91
app/Http/Controllers/StreamerPanelController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Champion;
|
||||
use App\Models\Streamer;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class StreamerPanelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('streamerpanel.index', [
|
||||
'streamers' => Streamer::with('champion')->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('streamerpanel.streamer-create', [
|
||||
'champions' => Champion::all(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate(['champion_id' => 'required|exists:champions,champion_id',
|
||||
'platform' => 'required|in:twitch,youtube,kick,douyu,huya',
|
||||
'username' => 'required|string',
|
||||
'displayname' => 'required|string',
|
||||
]);
|
||||
|
||||
Streamer::create($request->all());
|
||||
|
||||
Cache::forget('streamersListAllAPICache');
|
||||
|
||||
return redirect()->route('streamerpanel.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Streamer $streamer)
|
||||
{
|
||||
return view('streamerpanel.streamer-edit', [
|
||||
'streamer' => $streamer,
|
||||
'champions' => Champion::all(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Streamer $streamer)
|
||||
{
|
||||
$request->validate([
|
||||
'champion_id' => 'required|exists:champions,id',
|
||||
'platform' => 'required|in:twitch,youtube,kick,douyu,huya',
|
||||
'username' => 'required|string',
|
||||
'displayname' => 'required|string',
|
||||
]);
|
||||
|
||||
$streamer->update($request->all());
|
||||
|
||||
Cache::forget('streamersListAllAPICache');
|
||||
|
||||
return redirect()->route('streamerpanel.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Streamer $streamer)
|
||||
{
|
||||
$streamer->delete();
|
||||
|
||||
Cache::forget('streamersListAllAPICache');
|
||||
|
||||
return redirect()->route('streamerpanel.index');
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,11 @@ class Champion extends Model
|
||||
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
|
||||
{
|
||||
$url = 'https://cdn.communitydragon.org/latest/champion/'.$this->champion_id.'/splash-art';
|
||||
|
||||
43
app/Models/Streamer.php
Normal file
43
app/Models/Streamer.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Streamer extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['champion_id', 'platform', 'username', 'displayname'];
|
||||
|
||||
public function getPlatformAttribute($value): string
|
||||
{
|
||||
$platforms = [
|
||||
'twitch' => 'Twitch',
|
||||
'youtube' => 'YouTube',
|
||||
'kick' => 'Kick',
|
||||
'douyu' => 'Douyu',
|
||||
'huya' => 'Huya',
|
||||
];
|
||||
|
||||
return $platforms[$value];
|
||||
}
|
||||
|
||||
public function getStreamerUrlAttribute(): string
|
||||
{
|
||||
return match ($this->platform) {
|
||||
'Twitch' => "https://www.twitch.tv/{$this->username}",
|
||||
'YouTube' => "https://www.youtube.com/@{$this->username}",
|
||||
'Kick' => "https://kick.com/{$this->username}",
|
||||
'Douyu' => "https://www.douyu.com/{$this->username}",
|
||||
'Huya' => "https://www.huya.com/{$this->username}",
|
||||
};
|
||||
}
|
||||
|
||||
public function champion(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Champion::class, 'champion_id', 'champion_id');
|
||||
}
|
||||
}
|
||||
26
app/View/Components/Streamerpanel/StreamerCreateForm.php
Normal file
26
app/View/Components/Streamerpanel/StreamerCreateForm.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components\Streamerpanel;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class StreamerCreateForm extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct(public $champions)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.streamerpanel.streamer-create-form');
|
||||
}
|
||||
}
|
||||
26
app/View/Components/Streamerpanel/StreamersTable.php
Normal file
26
app/View/Components/Streamerpanel/StreamersTable.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components\Streamerpanel;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class StreamersTable extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct(public Collection $streamers)
|
||||
{
|
||||
$this->streamers = $streamers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View
|
||||
{
|
||||
return view('components.streamerpanel.streamers-table');
|
||||
}
|
||||
}
|
||||
60
composer.lock
generated
60
composer.lock
generated
@@ -118,16 +118,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.301.1",
|
||||
"version": "3.301.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba"
|
||||
"reference": "1d04b11a621eaceb389d2cfbd82bcdc423903796"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0a910d2b35e7087337cdf3569dc9b6ce232aafba",
|
||||
"reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1d04b11a621eaceb389d2cfbd82bcdc423903796",
|
||||
"reference": "1d04b11a621eaceb389d2cfbd82bcdc423903796",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -207,9 +207,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.301.1"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.301.4"
|
||||
},
|
||||
"time": "2024-03-15T18:14:42+00:00"
|
||||
"time": "2024-03-20T18:16:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "blade-ui-kit/blade-icons",
|
||||
@@ -5036,16 +5036,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.16.3",
|
||||
"version": "1.16.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-package-tools.git",
|
||||
"reference": "59db18c2e20d49a0b6d447bb1c654f6c123beb9e"
|
||||
"reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/59db18c2e20d49a0b6d447bb1c654f6c123beb9e",
|
||||
"reference": "59db18c2e20d49a0b6d447bb1c654f6c123beb9e",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53",
|
||||
"reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5084,7 +5084,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-package-tools/issues",
|
||||
"source": "https://github.com/spatie/laravel-package-tools/tree/1.16.3"
|
||||
"source": "https://github.com/spatie/laravel-package-tools/tree/1.16.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5092,7 +5092,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-07T07:35:57+00:00"
|
||||
"time": "2024-03-20T07:29:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-query-builder",
|
||||
@@ -8726,16 +8726,16 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "4775f35b2d70865807c89d32c8e7385b86eb0ace"
|
||||
"reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/4775f35b2d70865807c89d32c8e7385b86eb0ace",
|
||||
"reference": "4775f35b2d70865807c89d32c8e7385b86eb0ace",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/5b16e25a5355f1f3afdfc2f954a0a80aec4826a8",
|
||||
"reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8777,7 +8777,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/3.1.2"
|
||||
"source": "https://github.com/composer/pcre/tree/3.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8793,7 +8793,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-07T15:38:35+00:00"
|
||||
"time": "2024-03-19T10:26:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
@@ -9223,16 +9223,16 @@
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.6.9",
|
||||
"version": "1.6.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mockery/mockery.git",
|
||||
"reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06"
|
||||
"reference": "47065d1be1fa05def58dc14c03cf831d3884ef0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mockery/mockery/zipball/0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06",
|
||||
"reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06",
|
||||
"url": "https://api.github.com/repos/mockery/mockery/zipball/47065d1be1fa05def58dc14c03cf831d3884ef0b",
|
||||
"reference": "47065d1be1fa05def58dc14c03cf831d3884ef0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9244,8 +9244,8 @@
|
||||
"phpunit/phpunit": "<8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5 || ^9.6.10",
|
||||
"symplify/easy-coding-standard": "^12.0.8"
|
||||
"phpunit/phpunit": "^8.5 || ^9.6.17",
|
||||
"symplify/easy-coding-standard": "^12.1.14"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -9302,7 +9302,7 @@
|
||||
"security": "https://github.com/mockery/mockery/security/advisories",
|
||||
"source": "https://github.com/mockery/mockery"
|
||||
},
|
||||
"time": "2023-12-10T02:24:34+00:00"
|
||||
"time": "2024-03-19T16:15:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@@ -9738,16 +9738,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.62",
|
||||
"version": "1.10.63",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "cd5c8a1660ed3540b211407c77abf4af193a6af9"
|
||||
"reference": "ad12836d9ca227301f5fb9960979574ed8628339"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd5c8a1660ed3540b211407c77abf4af193a6af9",
|
||||
"reference": "cd5c8a1660ed3540b211407c77abf4af193a6af9",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ad12836d9ca227301f5fb9960979574ed8628339",
|
||||
"reference": "ad12836d9ca227301f5fb9960979574ed8628339",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9796,7 +9796,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-13T12:27:20+00:00"
|
||||
"time": "2024-03-18T16:53:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('streamers', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('champion_id');
|
||||
$table->enum('platform', ['twitch', 'youtube', 'kick', 'douyu', 'huya']);
|
||||
$table->string('username');
|
||||
$table->string('displayname');
|
||||
|
||||
$table->foreign('champion_id')->references('champion_id')->on('champions')->onDelete('cascade');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('streamers');
|
||||
}
|
||||
};
|
||||
1
dev_quickstart.bat
Normal file
1
dev_quickstart.bat
Normal file
@@ -0,0 +1 @@
|
||||
npm run dev-all
|
||||
@@ -2,6 +2,78 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url("/fonts/inter-v13-latin-100.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url("/fonts/inter-v13-latin-200.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url("/fonts/inter-v13-latin-300.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("/fonts/inter-v13-latin-regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url("/fonts/inter-v13-latin-500.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url("/fonts/inter-v13-latin-600.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url("/fonts/inter-v13-latin-700.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url("/fonts/inter-v13-latin-800.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url("/fonts/inter-v13-latin-900.woff2") format("woff2");
|
||||
}
|
||||
|
||||
.glow-shadow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -13,13 +85,18 @@
|
||||
animation: glow 4s infinite;
|
||||
--tw-scale-x: 1.02;
|
||||
--tw-scale-y: 1.02;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y))
|
||||
rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y))
|
||||
scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.shadow-md-splash {
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--splash-color), 0 2px 4px -2px var(--splash-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1),
|
||||
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--splash-color),
|
||||
0 2px 4px -2px var(--splash-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
|
||||
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
@@ -27,10 +104,12 @@
|
||||
opacity: 0.8;
|
||||
filter: blur(8px);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.45;
|
||||
filter: blur(11px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.8;
|
||||
filter: blur(8px);
|
||||
@@ -47,75 +126,22 @@
|
||||
box-shadow: 0 50vh 0 50vh #292524;
|
||||
}
|
||||
|
||||
/* inter-100 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url('/fonts/inter-v13-latin-100.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
.text-shadow-twitch {
|
||||
text-shadow: 1px 1px 2px #6441a5;
|
||||
}
|
||||
/* inter-200 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('/fonts/inter-v13-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
|
||||
.text-shadow-youtube {
|
||||
text-shadow: 1px 1px 2px #ff0000;
|
||||
}
|
||||
/* inter-300 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('/fonts/inter-v13-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
|
||||
.text-shadow-kick {
|
||||
text-shadow: 1px 1px 2px #53fc18;
|
||||
}
|
||||
/* inter-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('/fonts/inter-v13-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
|
||||
.text-shadow-douyu {
|
||||
text-shadow: 1px 1px 2px #ff5f3a;
|
||||
}
|
||||
/* inter-500 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('/fonts/inter-v13-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
/* inter-600 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url('/fonts/inter-v13-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
/* inter-700 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url('/fonts/inter-v13-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
/* inter-800 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url('/fonts/inter-v13-latin-800.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
/* inter-900 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('/fonts/inter-v13-latin-900.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
|
||||
.text-shadow-huya {
|
||||
text-shadow: 1px 1px 2px #ffaa06;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
about ' . $champion->name . ', ' . $champion->title . '. ' . substr($champion->lore, 0, 50) . '...')
|
||||
|
||||
@section('content')
|
||||
<x-champions.grid_info :champion="$champion"/>
|
||||
<x-champions.grid_info :champion="$champion" :streamers="$streamers"/>
|
||||
@endsection
|
||||
|
||||
@push('bottom_scripts')
|
||||
|
||||
@@ -7,26 +7,23 @@
|
||||
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>
|
||||
<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>
|
||||
|
||||
<div class="container mx-auto p-4 flex items-center justify-center mt-3">
|
||||
<div class="w-screen grid grid-cols-1 md-grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
<div class="container flex items-center justify-center p-4 mx-auto mt-3">
|
||||
<div class="grid w-screen grid-cols-1 gap-5 md-grid-cols-2 lg:grid-cols-3">
|
||||
<div
|
||||
class="relative rounded-2xl bg-stone-800/40 border border-neutral-300/5 shadow-sm shadow-stone-800/80 lg:col-span-2">
|
||||
<div class="aspect-w-16 aspect-h-9 glow-shadow absolute inset-0 rounded-2xl"
|
||||
class="relative border shadow-sm aspect-video rounded-2xl bg-stone-800/40 border-neutral-300/5 shadow-stone-800/80 lg:col-span-2">
|
||||
<div class="absolute inset-0 aspect-video glow-shadow rounded-2xl"
|
||||
style="--splash-color: {{ $champion->splash_color }}"></div>
|
||||
<div class="aspect-w-16 aspect-h-9 overflow-hidden rounded-2xl relative">
|
||||
<img
|
||||
src="//wsrv.nl/?url={{ $champion->getChampionImageAttribute(false) }}&w=880&output=webp&q=85&il"
|
||||
<div class="relative overflow-hidden aspect-video rounded-2xl">
|
||||
<img src="//wsrv.nl/?url={{ $champion->getChampionImageAttribute(false) }}&w=880&output=webp&q=85&il"
|
||||
alt="{{ $champion->name }} Splash Art"
|
||||
class="w-full h-full object-cover transform scale-100 transition-transform duration-700 hover:scale-105 z-10"
|
||||
>
|
||||
class="z-10 object-cover w-full h-full transition-transform duration-700 transform scale-100 hover:scale-105">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-2xl border border-3 border-white/10 lg:col-start-3 shadow-md transition-all duration-700"
|
||||
<div class="transition-all duration-700 border shadow-md rounded-2xl border-3 border-white/10 lg:col-start-3"
|
||||
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">
|
||||
@@ -34,74 +31,86 @@
|
||||
|
||||
<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 }}.
|
||||
</li>
|
||||
<li class="text-neutral-100 hyphens-auto text-base font-medium leading-loose" lang="en">
|
||||
<span class="font-bold">Popular Positions:</span> @foreach($champion->lanes->roles as $lane)
|
||||
<span
|
||||
class="inline-block lowercase capitalize-first">{{$lane}} @svg(getRoleIconSvg($lane), 'w-5 h-5 inline-block')
|
||||
<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="inline-block lowercase capitalize-first">{{ $lane }} @svg(getRoleIconSvg($lane), 'w-5 h-5 inline-block')
|
||||
@if (!$loop->last)
|
||||
-
|
||||
@endif</span>
|
||||
@endif
|
||||
</span>
|
||||
@endforeach
|
||||
</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">
|
||||
<span class="font-bold">Blue Essence Cost:</span>
|
||||
<x-icon-lcu-be-svg class="inline-block w-4" /> {{ $champion->price_be }} BE
|
||||
</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">
|
||||
<span class="font-bold">Riot Points Cost:</span>
|
||||
<x-icon-RiotPoints class="inline-block w-4" /> {{ $champion->price_rp }} RP
|
||||
</li>
|
||||
<li class="text-neutral-100 hyphens-auto leading-loose font-medium" lang="en">
|
||||
<span class="font-bold">Roles:</span> @foreach($champion->roles as $role)
|
||||
<span
|
||||
class="inline-block lowercase capitalize-first">{{$role}}
|
||||
<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="inline-block lowercase capitalize-first">{{ $role }}
|
||||
@if (!$loop->last)
|
||||
-
|
||||
@endif</span>
|
||||
@endif
|
||||
</span>
|
||||
@endforeach
|
||||
</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
|
||||
class="inline-block lowercase capitalize-first">{{ $champion->attack_type }}</span>
|
||||
</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 }}
|
||||
</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 }}
|
||||
</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
|
||||
class="font-mono font-medium">{{ $champion->champion_id }}</span>
|
||||
</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 }}
|
||||
</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 }}
|
||||
</li>
|
||||
</ul>
|
||||
</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 }};">
|
||||
<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" lang="en">
|
||||
{{$champion->lore}}
|
||||
{{ $champion->name }} Streamers</h4>
|
||||
<p class="text-neutral-100/75 hyphens-auto mt-2.5 leading-loose text-center text-sm" lang="en">
|
||||
A list of streamers who play {{ $champion->name }} and are atleast Diamond 2 or higher.
|
||||
</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 drop-shadow-lg text-shadow-{{ strtolower($streamer->platform) }}">
|
||||
{{ $streamer->displayname }}
|
||||
</a>
|
||||
</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"
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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 }};">
|
||||
<div class="p-4">
|
||||
<h4 class="text-center text-xl font-semibold text-neutral-100 uppercase mt-2.5 shadow-sm">
|
||||
@@ -109,17 +118,17 @@
|
||||
<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">
|
||||
@foreach ($champion->skins as $key => $skin)
|
||||
<div class="group flex flex-col">
|
||||
<div class="flex flex-col group">
|
||||
<a href="/skin/{{ $skin->slug }}">
|
||||
<img
|
||||
src="//wsrv.nl/?url={{ $skin->getSkinImageAttribute() }}&w=450&output=webp&q=70&il"
|
||||
<img src="//wsrv.nl/?url={{ $skin->getSkinImageAttribute() }}&w=450&output=webp&q=70&il"
|
||||
alt="{{ $champion->name }} {{ $skin->name }} Splash Art"
|
||||
@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">
|
||||
</a>
|
||||
<div>
|
||||
|
||||
<p class="align-bottom text-center text-neutral-100 text-sm mt-1.5 items-center">
|
||||
<p
|
||||
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">
|
||||
{{ $skin->skin_name }}
|
||||
@@ -133,6 +142,17 @@
|
||||
</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>
|
||||
</section>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</button>
|
||||
<div id="navbar-default" class="hidden w-full md:block md:w-auto">
|
||||
<ul
|
||||
class="flex flex-col p-2 items-center md:flex-row md:space-x-6 md:mt-0 md:border-0 md:bg-white dark:bg-stone-800 md:dark:bg-stone-800 dark:border-stone-700">
|
||||
class="flex flex-col items-center p-2 md:flex-row md:space-x-6 md:mt-0 md:border-0 md:bg-white dark:bg-stone-800 md:dark:bg-stone-800 dark:border-stone-700">
|
||||
<li>
|
||||
<a href="{{ route('champions.index') }}"
|
||||
class="flex py-2 pl-3 pr-2 rounded hover:bg-stone-100 md:hover:bg-transparent
|
||||
|
||||
36
resources/views/components/panel-navbar.blade.php
Normal file
36
resources/views/components/panel-navbar.blade.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<nav class="drop-shadow-md border-stone-200 bg-stone-800">
|
||||
<div class="flex flex-wrap items-center justify-between max-w-screen-xl p-4 mx-auto">
|
||||
<a href="/streamerpanel" class="flex items-center transition-transform hover:scale-105">
|
||||
<x-logo class="w-auto mr-2 transition-transform h-9 hover:scale-125" alt="Heimerdinger Logo" />
|
||||
<span class="self-center text-2xl font-semibold text-orange-400 whitespace-nowrap">Streamer Panel</span>
|
||||
<span class="sr-only">Streamer Panel</span>
|
||||
</a>
|
||||
<button data-collapse-toggle="navbar-default" type="button"
|
||||
class="inline-flex items-center justify-center w-10 h-10 p-2 text-sm rounded-lg text-stone-500 md:hidden hover:bg-stone-100 focus:outline-none focus:ring-2 focus:ring-stone-200 dark:text-stone-400 dark:hover:bg-stone-700 dark:focus:ring-stone-600"
|
||||
aria-controls="navbar-default" aria-expanded="false">
|
||||
<span class="sr-only">Open main menu</span>
|
||||
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
|
||||
viewBox="0 0 17 14">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M1 1h15M1 7h15M1 13h15" />
|
||||
</svg>
|
||||
</button>
|
||||
<div id="navbar-default" class="hidden w-full md:block md:w-auto">
|
||||
<ul
|
||||
class="flex flex-col items-center p-2 md:flex-row md:space-x-6 md:mt-0 md:border-0 md:bg-white dark:bg-stone-800 md:dark:bg-stone-800 dark:border-stone-700">
|
||||
<li>
|
||||
<a href="{{ route('streamerpanel.index') }}"
|
||||
class="flex py-2 pl-3 pr-2 rounded hover:bg-stone-100 md:hover:bg-transparent md:border-0 md:p-0 md:dark:hover:text-orange-400 dark:hover:bg-stone-700 dark:hover:text-white md:dark:hover:bg-transparent
|
||||
{{ request()->routeIs('streamerpanel.*') ? 'text-orange-400 font-medium' : 'text-white' }}">
|
||||
Streamers</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"
|
||||
class="flex py-2 pl-3 pr-2 rounded hover:bg-stone-100 md:hover:bg-transparent md:border-0 md:hover:text-orange-500 md:p-0 md:dark:hover:text-orange-400 dark:hover:bg-stone-700 dark:hover:text-white md:dark:hover:bg-transparent
|
||||
{{ request()->routeIs('streamerrequests.*') ? 'text-orange-400 font-medium' : 'text-white' }}">
|
||||
Streamer Requests</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -1,23 +1,23 @@
|
||||
@use('Carbon\Carbon')
|
||||
|
||||
<div class="container mx-auto p-4 flex flex-col items-center justify-center mt-3">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-12 auto-cols-max w-full">
|
||||
<div class="container flex flex-col items-center justify-center p-4 mx-auto mt-3">
|
||||
<div class="grid w-full grid-cols-1 gap-12 md:grid-cols-2 auto-cols-max">
|
||||
@foreach($posts as $post)
|
||||
@if($post->hidden)
|
||||
@continue
|
||||
@endif
|
||||
<article class="inline-block text-gray-200 bg-stone-800/40 shadow-md rounded-2xl border border-stone-800 hover:border-orange-500/10 hover:shadow-orange-500/10 items-center h-80 relative">
|
||||
<article class="relative items-center inline-block text-gray-200 border shadow-md bg-stone-800/40 rounded-2xl border-stone-800 hover:border-orange-500/10 hover:shadow-orange-500/10 h-80">
|
||||
<span
|
||||
class="absolute top-4 left-4 text-sm text-gray-100 font-medium bg-black/60 px-1 py-1 rounded-lg">
|
||||
class="absolute px-1 py-1 text-sm font-medium text-gray-100 rounded-lg top-4 left-4 bg-black/60">
|
||||
<abbr itemprop="datePublished">{{ Carbon::parse($post->date)->format('F d, Y') }}</abbr>
|
||||
</span>
|
||||
<img src="{{ $post->thumbnail }}" alt="Post Thumbnail" class="w-full h-48 object-cover rounded-t-2xl">
|
||||
<img src="{{ $post->thumbnail }}" alt="Post Thumbnail" class="object-cover w-full h-48 aspect-video rounded-t-2xl">
|
||||
<div class="p-4">
|
||||
<h2 class="text-xl font-bold mb-2 line-clamp-1" itemprop="name">{{ $post->title }}</h2>
|
||||
<h2 class="mb-2 text-xl font-bold line-clamp-1" itemprop="name">{{ $post->title }}</h2>
|
||||
<p class="text-sm line-clamp-3" itemprop="headline">{{ $post->description }}</p>
|
||||
</div>
|
||||
<a href="{{ route('posts.show', $post->slug)}}" itemprop="url"
|
||||
class="absolute bottom-4 right-4 text-sm text-orange-400 hover:text-orange-600">Read more</a>
|
||||
class="absolute text-sm text-orange-400 bottom-4 right-4 hover:text-orange-600">Read more</a>
|
||||
</article>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="grid w-screen grid-cols-1 gap-5 md-grid-cols-2 lg:grid-cols-3">
|
||||
<div
|
||||
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="absolute inset-0 aspect-w-16 aspect-h-9 glow-shadow rounded-2xl"
|
||||
<div class="absolute inset-0 aspect-video glow-shadow rounded-2xl"
|
||||
style="--splash-color: {{$skin->splash_color}}"></div>
|
||||
<img src="//wsrv.nl/?url={{ $skin->getSkinImageAttribute() }}&w=840&output=webp&q=70"
|
||||
alt="{{$skin->skin_name}} Splash Art"
|
||||
|
||||
11
resources/views/components/streamerpanel/home.blade.php
Normal file
11
resources/views/components/streamerpanel/home.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<section class="max-w-screen-xl mx-auto mt-12">
|
||||
<h1
|
||||
class="text-2xl font-bold text-center text-transparent uppercase sm:text-4xl bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text">
|
||||
Streamers</h1>
|
||||
<div class="flex justify-center mt-4">
|
||||
<a href="{{ route('streamerpanel.streamers.create') }}"
|
||||
class="flex items-center justify-center px-4 py-2 text-sm font-medium text-white bg-orange-500 rounded-md hover:bg-orange-600 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2">
|
||||
Add Streamer
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,37 @@
|
||||
<form action="{{ route('streamerpanel.store') }}" method="POST" class="w-10/12 mx-auto ">
|
||||
@csrf
|
||||
<div class="flex flex-col space-y-4">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<label for="champion_id" class="text-lg font-semibold text-orange-400">Champion</label>
|
||||
<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)
|
||||
<option value="{{ $champion->champion_id }}">{{ $champion->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<label for="platform" class="text-lg font-semibold text-orange-400">Platform</label>
|
||||
<select name="platform" id="platform" class="w-full p-2 text-white rounded-md bg-stone-800">
|
||||
<option value="twitch">Twitch</option>
|
||||
<option value="youtube">YouTube</option>
|
||||
<option value="kick">Kick</option>
|
||||
<option value="douyu">Douyu</option>
|
||||
<option value="huya">Huya</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<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" />
|
||||
</div>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<label for="displayname" class="text-lg font-semibold text-orange-400">Display Name</label>
|
||||
<input type="text" name="displayname" id="displayname"
|
||||
class="w-full p-2 text-white rounded-md bg-stone-800" />
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="px-4 py-2 mt-3 text-white bg-orange-500 rounded-md">Add Streamer</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,49 @@
|
||||
@push('top_scripts')
|
||||
<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" />
|
||||
@endpush
|
||||
<div class="w-10/12 mx-auto">
|
||||
<div id="streamers-wrapper"></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@push('bottom_scripts')
|
||||
<script>
|
||||
new gridjs.Grid({
|
||||
columns: [
|
||||
"Champion",
|
||||
"Streamer Name",
|
||||
{
|
||||
name: "URL",
|
||||
formatter: (_, row) => gridjs.html(
|
||||
`<a href="${row.cells[2].data}" target="_blank">${row.cells[2].data}</a>`)
|
||||
},
|
||||
{
|
||||
name: "Actions",
|
||||
formatter: (_, row) => gridjs.html(row.cells[3].data)
|
||||
}
|
||||
],
|
||||
data: [
|
||||
@foreach ($streamers as $streamer)
|
||||
["{{ $streamer->champion->name }}", "{{ $streamer->displayname }}",
|
||||
"{{ $streamer->streamer_url }}", `<a href="/streamerpanel/edit/{{ $streamer->id }}">✏️</a> <a href="/streamerpanel/delete/{{ $streamer->id }}" onclick="event.preventDefault(); if (confirm('Are you sure you want to delete this streamer?')) { document.getElementById('delete-form-{{ $streamer->id }}').submit(); }">❌</a>
|
||||
<form id="delete-form-{{ $streamer->id }}" action="/streamerpanel/delete/{{ $streamer->id }}" method="POST" style="display: none;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
</form>`
|
||||
],
|
||||
@endforeach
|
||||
],
|
||||
search: true,
|
||||
pagination: {
|
||||
limit: 20
|
||||
},
|
||||
language: {
|
||||
'search': {
|
||||
'placeholder': '🔍 Search streamers...'
|
||||
}
|
||||
}
|
||||
}).render(document.getElementById("streamers-wrapper"));
|
||||
</script>
|
||||
@endpush
|
||||
58
resources/views/layouts/streamerpanel.blade.php
Normal file
58
resources/views/layouts/streamerpanel.blade.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- DarkReader somehow thinks the website isn't dark by default,
|
||||
this tells darkreader to disable on the site. -->
|
||||
<meta name="darkreader-lock">
|
||||
|
||||
<META NAME="robots" CONTENT="noindex,nofollow">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/icons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/icons/favicon-16x16.png">
|
||||
<link rel="manifest" href="/img/icons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/img/icons/safari-pinned-tab.svg" color="#e6855e">
|
||||
<link rel="shortcut icon" href="/img/icons/favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="#ff7c47">
|
||||
<meta name="msapplication-config" content="/img/icons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ff7c47">
|
||||
|
||||
<title>@yield('title')</title>
|
||||
<meta name="description" content="@yield('description')">
|
||||
|
||||
@stack('meta_tags')
|
||||
|
||||
<!-- OpenGraph -->
|
||||
<meta property="og:site_name" content="Heimerdinger.LoL">
|
||||
<meta property="og:title" content="@yield('title')">
|
||||
<meta property="og:url" content="{{ url()->current() }}">
|
||||
<meta property="og:description" content="@yield('description')">
|
||||
<meta property="og:locale" content="en">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="https://cdn.heimerdinger.lol/og-img-home.png">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:domain" content="heimerdinger.lol">
|
||||
<meta property="twitter:title" content="@yield('title')">
|
||||
<meta property="twitter:description" content="@yield('description')">
|
||||
<meta property="twitter:image" content="https://cdn.heimerdinger.lol/og-img-home.png">
|
||||
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
|
||||
@stack('top_scripts')
|
||||
<x-analytics.plausible />
|
||||
</head>
|
||||
|
||||
<body class="antialiased bg-stone-900 dark scroll-smooth">
|
||||
<x-panel-navbar />
|
||||
@yield('content')
|
||||
@stack('bottom_scripts')
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -14,34 +14,31 @@
|
||||
|
||||
@section('content')
|
||||
<a href="{{ route('posts.index') }}"
|
||||
class="block mt-8 text-center text-orange-400 text-sm uppercase font-medium hover:underline">Back
|
||||
class="block mt-8 text-sm font-medium text-center text-orange-400 uppercase hover:underline">Back
|
||||
to
|
||||
posts</a>
|
||||
<article class="max-w-screen-md mx-auto mt-2 prose prose-stone prose-invert" itemscope
|
||||
itemtype="https://schema.org/BlogPosting"
|
||||
itemid="{{url()->current()}}">
|
||||
itemtype="https://schema.org/BlogPosting" itemid="{{ url()->current() }}">
|
||||
<meta itemprop="wordCount" content="{{ str_word_count($post->contents) }}">
|
||||
<h3 class="not-prose text-sm text-center text-orange-100 font-semibold" itemprop="datePublished">
|
||||
<h3 class="text-sm font-semibold text-center text-orange-100 not-prose" itemprop="datePublished">
|
||||
{{ Carbon::parse($post->date)->format('F d, Y') }}
|
||||
</h3>
|
||||
<img src="{{ $post->thumbnail }}" alt="{{ $post->title }} Thumbnail"
|
||||
class="not-prose aspect-video max-h-64 w-auto mt-2 mb-2 mx-auto rounded-3xl border-orange-500/40 border-2"/>
|
||||
class="w-auto mx-auto mt-2 mb-2 border-2 not-prose aspect-video max-h-64 rounded-3xl border-orange-500/40" />
|
||||
<meta itemprop="thumbnailUrl" content="{{ $post->thumbnail }}" />
|
||||
<div>
|
||||
<h1
|
||||
class="not-prose 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" itemprop="headline">
|
||||
<h1 class="text-3xl font-bold text-center text-transparent uppercase not-prose sm:text-4xl bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text"
|
||||
itemprop="headline">
|
||||
“{{ $post->title }}”</h1>
|
||||
<h2 class="not-prose text-center text-orange-400 text-sm italic" itemprop="description">
|
||||
<h2 class="text-sm italic text-center text-orange-400 not-prose" itemprop="description">
|
||||
“{{ $post->description }}”
|
||||
</h2>
|
||||
<p>
|
||||
{{ $post->contents }}
|
||||
</p>
|
||||
<p class="mt-3 text-sm text-center">
|
||||
Tagged with: <span itemprop="keywords"
|
||||
class="italic">
|
||||
{{ isset($post->tags) ? implode(', ', $post->tags)
|
||||
: 'League of Legends' }}</span>
|
||||
Tagged with: <span itemprop="keywords" class="italic">
|
||||
{{ isset($post->tags) ? implode(', ', $post->tags) : 'League of Legends' }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
9
resources/views/streamerpanel/index.blade.php
Normal file
9
resources/views/streamerpanel/index.blade.php
Normal file
@@ -0,0 +1,9 @@
|
||||
@extends('layouts.streamerpanel')
|
||||
|
||||
@section('title', 'Streamer Panel • Heimerdinger.LoL')
|
||||
@section('description', 'Heimerdinger.LoL: Streamer Panel for managing your streamer requests.')
|
||||
|
||||
@section('content')
|
||||
<x-streamerpanel.home />
|
||||
<x-streamerpanel.streamerstable :streamers="$streamers" />
|
||||
@endsection
|
||||
15
resources/views/streamerpanel/streamer-create.blade.php
Normal file
15
resources/views/streamerpanel/streamer-create.blade.php
Normal file
@@ -0,0 +1,15 @@
|
||||
@extends('layouts.streamerpanel')
|
||||
|
||||
@section('title', 'Streamer Panel • Heimerdinger.LoL')
|
||||
@section('description', 'Heimerdinger.LoL: Streamer Panel for managing your streamer requests.')
|
||||
|
||||
@section('content')
|
||||
<section class="max-w-screen-xl mx-auto mt-12">
|
||||
<h1
|
||||
class="text-2xl font-bold text-center text-transparent uppercase sm:text-4xl bg-gradient-to-bl from-orange-300 to-orange-500 bg-clip-text">
|
||||
Add a new Streamer</h1>
|
||||
<x-streamerpanel.streamer-create-form :champions="$champions" />
|
||||
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
@@ -1,12 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register API routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider and all of them will
|
||||
| be assigned to the "api" middleware group. Make something great!
|
||||
|
|
||||
*/
|
||||
use App\Http\Controllers\StreamerController;
|
||||
|
||||
Route::get('/streamers', [StreamerController::class, 'all']);
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Http\Controllers\SummonerIconController;
|
||||
use App\Http\Requests\ContactSubmissionRequest;
|
||||
use App\Models\Champion;
|
||||
use App\Models\SummonerIcon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Spatie\Honeypot\ProtectAgainstSpam;
|
||||
use Spatie\Sheets\Sheet;
|
||||
@@ -79,3 +80,11 @@ Route::get('/resource/sitemap', static fn () => (new HTMLSitemapController())->i
|
||||
|
||||
// Pulse
|
||||
Route::get(config('app.login_route'), static fn () => redirect('/pulse'))->name('login')->middleware('auth.basic');
|
||||
|
||||
// Streamer Panel
|
||||
Route::get('/streamerpanel', static fn () => (new \App\Http\Controllers\StreamerPanelController())->index())->name('streamerpanel.index')->middleware('auth.basic');
|
||||
Route::get('/streamerpanel/add', static fn () => (new \App\Http\Controllers\StreamerPanelController())->create())->name('streamerpanel.streamers.create')->middleware('auth.basic');
|
||||
Route::post('/streamerpanel/add', static fn (Request $request) => (new \App\Http\Controllers\StreamerPanelController())->store($request))->name('streamerpanel.store')->middleware('auth.basic');
|
||||
Route::get('/streamerpanel/edit/{streamer}', static fn (\App\Models\Streamer $streamer) => (new \App\Http\Controllers\StreamerPanelController())->edit($streamer))->name('streamerpanel.edit')->middleware('auth.basic');
|
||||
Route::post('/streamerpanel/edit/{streamer}', static fn (Request $request, \App\Models\Streamer $streamer) => (new \App\Http\Controllers\StreamerPanelController())->update($request, $streamer))->name('streamerpanel.update')->middleware('auth.basic');
|
||||
Route::delete('/streamerpanel/delete/{streamer}', static fn (\App\Models\Streamer $streamer) => (new \App\Http\Controllers\StreamerPanelController())->destroy($streamer))->name('streamerpanel.destroy')->middleware('auth.basic');
|
||||
|
||||
@@ -5,6 +5,7 @@ module.exports = {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
'./resources/**/*.blade.php',
|
||||
'./resources/**/**/*.blade.php',
|
||||
'./resources/**/*.js',
|
||||
'./resources/**/*.vue',
|
||||
'./node_modules/flowbite/**/*.js',
|
||||
@@ -25,11 +26,15 @@ module.exports = {
|
||||
fontFamily: {
|
||||
sans: ['Inter var', 'Inter', 'sans-serif', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
colors: {
|
||||
twitch: '#6441a5',
|
||||
youtube: '#FF0000',
|
||||
kick: '#53fc18',
|
||||
douyu: '#ff5f3a',
|
||||
huya: '#ffaa06'
|
||||
}
|
||||
},
|
||||
},
|
||||
corePlugins: {
|
||||
aspectRatio: false,
|
||||
},
|
||||
variants: {
|
||||
extend: {
|
||||
textColor: ['group-hover'],
|
||||
@@ -37,7 +42,6 @@ module.exports = {
|
||||
},
|
||||
plugins: [
|
||||
require('flowbite/plugin'),
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
require('tailwind-capitalize-first-letter'),
|
||||
require('@tailwindcss/typography'),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user