feat/factory_creation (#1)
Prepping for launch. Reviewed-on: #1 Co-authored-by: Paul Couture <paul@paulcouture.com> Co-committed-by: Paul Couture <paul@paulcouture.com>
This commit was merged in pull request #1.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
APP_NAME="No Agenda Art Generator"
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:H840ho2ltTKV3IC1FQ333AaU8iW2zsn6ma67qhZWerk=
|
||||
APP_KEY=base64:laravel_key_generated_by_app
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://127.0.0.1
|
||||
|
||||
@@ -9,11 +9,11 @@ LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=mydb_p@ssw0rd
|
||||
DB_DATABASE=database_database_from_docker_env
|
||||
DB_USERNAME=database_username_from_docker_env
|
||||
DB_PASSWORD="docker_database_password_from_docker_env"
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
|
||||
5
site/.yarnrc
Normal file
5
site/.yarnrc
Normal file
@@ -0,0 +1,5 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
yarn-path ".yarn/releases/yarn-1.22.19.cjs"
|
||||
51
site/app/Console/Commands/AddMissingArtworkIdsToEpisodes.php
Normal file
51
site/app/Console/Commands/AddMissingArtworkIdsToEpisodes.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AddMissingArtworkIdsToEpisodes extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'naart:artwork-to-episodes';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$oldEpisodes = DB::connection('legacy')->select('SELECT * FROM episodes WHERE artwork_id IS NOT NULL AND published = 1');
|
||||
foreach($oldEpisodes as $oldEpisode) {
|
||||
$this->info('Checking old episode ' . $oldEpisode->show_date);
|
||||
$episode = Episode::where('legacy_id', $oldEpisode->id)->first();
|
||||
$artwork = Artwork::where('legacy_id', $oldEpisode->artwork_id)->first();
|
||||
if ($episode && $artwork) {
|
||||
$this->line('Have artwork ' . $artwork->title . ' for episode ' . $episode->title);
|
||||
$episode->artwork_id = $artwork->id;
|
||||
$episode->timestamps = false;
|
||||
if ($episode->isDirty()) {
|
||||
$this->info('I need to update this.');
|
||||
//$episode->save();
|
||||
} else {
|
||||
$this->line('No Change Needed.');
|
||||
}
|
||||
} else {
|
||||
$this->error('I am lost.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
site/app/Console/Commands/GetMissingArtworkMovedCommand.php
Normal file
125
site/app/Console/Commands/GetMissingArtworkMovedCommand.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\User;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Artwork;
|
||||
use ImageOptimizer;
|
||||
|
||||
class GetMissingArtworkMovedCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'naart:wrapup';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$missingArtworks = DB::connection('legacy')->select('SELECT * FROM artworks WHERE id > 30835 AND approved_by IS NOT NULL');
|
||||
foreach ($missingArtworks as $missingArtwork) {
|
||||
$localPath = '/legacypublic' . $missingArtwork->path . '/' . $missingArtwork->filename;
|
||||
$user = User::where('legacy_id', $missingArtwork->user_id)->with('artists')->first();
|
||||
$artwork = Artwork::where('legacy_id', $missingArtwork->id)->first();
|
||||
$episode = Episode::where('legacy_id', $missingArtwork->episode_id)->first();
|
||||
$approver = User::where('legacy_id', $missingArtwork->approved_by)->with('artists')->first();
|
||||
if ($artwork) {
|
||||
$this->line('Artwork ID: ' . $artwork->id);
|
||||
}
|
||||
if ($episode) {
|
||||
$this->line('Episode: ' . $episode->episode_number . ' "' . $episode->title . '"');
|
||||
}
|
||||
if (!$artwork) {
|
||||
$newFilename = $this->uniqueName($episode, $user, $missingArtwork);
|
||||
$state = [
|
||||
'title' => $missingArtwork->title,
|
||||
'description' => '',
|
||||
'artist_id' => $user->artists->first()->id,
|
||||
'episode_id' => $episode->id,
|
||||
'podcast_id' => 1,
|
||||
'overlay_id' => null,
|
||||
'filename' => $newFilename . '.jpg',
|
||||
'created_at' => Carbon::parse($missingArtwork->created_at),
|
||||
'updated_at' => Carbon::parse($missingArtwork->updated_at),
|
||||
'legacy_id' => $missingArtwork->id,
|
||||
'approved_by' => $approver->artists->first()->id,
|
||||
];
|
||||
$artwork = Artwork::factory()->state($state)->create();
|
||||
}
|
||||
$this->line('Artist: ' . $user->artists->first()->name);
|
||||
$this->line($localPath);
|
||||
$filename = 'artworks/' . $artwork->filename;
|
||||
$thumbnailName = 'thumbnails/' . $artwork->filename;
|
||||
if (Storage::disk('static')->exists($filename)) {
|
||||
$this->error($filename . ' already exists. ' . Storage::disk('static')->size($filename));
|
||||
}
|
||||
if (Storage::disk('static')->exists($thumbnailName)) {
|
||||
$this->error($thumbnailName . ' already exists. ' . Storage::disk('static')->size($thumbnailName));
|
||||
}
|
||||
$img = Image::make($localPath)
|
||||
->resize(3000, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100);
|
||||
$thumbImg = Image::make($localPath)
|
||||
->resize(512, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100);
|
||||
$imgLocation = Storage::disk('static')->put($filename, $img);
|
||||
$thumbLocation = Storage::disk('static')->put($thumbnailName, $thumbImg);
|
||||
$size_before = Storage::disk('static')->size($filename);
|
||||
$thumb_size_before = Storage::disk('static')->size($thumbnailName);
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path($filename));
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path($thumbnailName));
|
||||
$size_after = Storage::disk('static')->size($filename);
|
||||
$thumb_size_after = Storage::disk('static')->size($thumbnailName);
|
||||
$diff = $size_before - $size_after;
|
||||
$thumbDiff = $thumb_size_before - $thumb_size_after;
|
||||
$this->line('Filesize before: ' . $size_before);
|
||||
$this->line('Filesize after: ' . $size_after);
|
||||
$this->line('Thumb Filesize before: ' . $thumb_size_before);
|
||||
$this->line('Thumb Filesize after: ' . $thumb_size_after);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkExistingFilename($name) {
|
||||
$checkArtwork = Artwork::where('filename', $name . '.jpg')->count();
|
||||
return $checkArtwork;
|
||||
}
|
||||
|
||||
private function uniqueName($episode, $user, $missingArtwork) {
|
||||
$i = 0;
|
||||
$uniqueFilename = $episode->episode_date->format('Y/m/') . Str::slug($user->artists->first()->name . '-' . $missingArtwork->title) . '_' . $missingArtwork->id;
|
||||
$exists = $this->checkExistingFilename($uniqueFilename);
|
||||
if (!$exists) {
|
||||
return $uniqueFilename;
|
||||
}
|
||||
while(!$exists) {
|
||||
$i++;
|
||||
$uniqueFilename = $uniqueFilename . '_v' . $i;
|
||||
$exists = $this->checkExistingFilename($uniqueFilename);
|
||||
}
|
||||
return $uniqueFilename;
|
||||
}
|
||||
}
|
||||
46
site/app/Console/Commands/LegacyNginxMappingCommand.php
Normal file
46
site/app/Console/Commands/LegacyNginxMappingCommand.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Artwork;
|
||||
|
||||
class LegacyNginxMappingCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'naart:legacy-nginx-mapping';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$oldLocations = [];
|
||||
$newLocations = [];
|
||||
$this->line('# legacy_mappings.conf');
|
||||
$this->line('');
|
||||
$this->line('map $uri $new_location {');
|
||||
$artworks = Artwork::whereNotNull('legacy_filename')->get();
|
||||
foreach ($artworks as $artwork) {
|
||||
if (!in_array($artwork->legacy_filename, $oldLocations) && !in_array($artwork->legacy_filename, $newLocations)) {
|
||||
$oldLocations[] = $artwork->legacy_filename;
|
||||
$newLocations[] = $artwork->legacy_filename;
|
||||
$this->line(' "' . $artwork->legacy_filename . '" "/legacy-asset/?legacy_filename=' . urlencode($artwork->legacy_filename) . '";');
|
||||
}
|
||||
}
|
||||
$this->line(' default $uri;');
|
||||
$this->line('}');
|
||||
$this->line('');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
|
||||
class MapLegacyArtworkToLegacyEpisodeCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'naart:map-legacy';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Maps legacy artwork to the legacy episode it related to.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$artworks = Artwork::whereNotNull('legacy_id')->get();
|
||||
foreach ($artworks as $artwork) {
|
||||
if ($artwork->id > 76200) {
|
||||
$legacyDetailResponse = $this->getArtworkInfoFromApi($artwork->legacy_id);
|
||||
$response = $legacyDetailResponse->object();
|
||||
if ($response->artwork->episode_id) {
|
||||
$episode = Episode::where('legacy_id', $response->artwork->episode_id)->first();
|
||||
if ($episode) {
|
||||
$artwork->episode_id = $episode->id;
|
||||
$this->line('Artwork ID ' . $artwork->id . ' is mapped to Episode ID ' . $episode->id);
|
||||
if ($artwork->isDirty()) {
|
||||
$this->line('This is a new mapping.');
|
||||
$artwork->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getArtworkInfoFromApi($artwork_legacy_id) {
|
||||
$response = Http::timeout(180)
|
||||
->get('https://noagendaartgenerator.com/artworkapi/' . $artwork_legacy_id,
|
||||
[
|
||||
'p' => '7476',
|
||||
]
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
|
||||
class MapSelectedLegacyArtworkToEpisode extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'naart:map-selected';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Maps the correct artwork selected to the legacy episodes';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$episodes = Episode::all();
|
||||
foreach ($episodes as $episode) {
|
||||
$this->line('Checking episode ' . $episode->episode_number);
|
||||
$legacyEpisodeResponse = $this->getEpisodeFromApi($episode->episode_number);
|
||||
$response = $legacyEpisodeResponse->object();
|
||||
if ($response->episode->artwork_id && $response->episode->artwork_id + 0 > 0) {
|
||||
$selectedArtwork = Artwork::where('legacy_id', $response->episode->artwork_id)->first();
|
||||
if ($selectedArtwork) {
|
||||
$episode->artwork_id = $selectedArtwork->id;
|
||||
$this->line('Artwork ID ' . $selectedArtwork->id . ' marked as episode artwork for episode ' . $episode->episode_number);
|
||||
if ($episode->isDirty()) {
|
||||
$this->line('This is a new mapping.');
|
||||
$episode->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getEpisodeFromApi($episode_legacy_id) {
|
||||
$response = Http::timeout(180)
|
||||
->get('https://noagendaartgenerator.com/episodeapi/' . $episode_legacy_id,
|
||||
[
|
||||
'p' => '7476',
|
||||
]
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
27
site/app/Helpers/pcagHelpers.php
Normal file
27
site/app/Helpers/pcagHelpers.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('numberSuffix')) {
|
||||
function numberSuffix($number) {
|
||||
if (!is_int($number) || $number < 1) {
|
||||
return $number;
|
||||
}
|
||||
|
||||
$lastDigit = $number % 10;
|
||||
$secondLastDigit = ($number / 10) % 10;
|
||||
|
||||
if ($secondLastDigit == 1) {
|
||||
return 'th';
|
||||
}
|
||||
|
||||
switch ($lastDigit) {
|
||||
case 1:
|
||||
return 'st';
|
||||
case 2:
|
||||
return 'nd';
|
||||
case 3:
|
||||
return 'rd';
|
||||
default:
|
||||
return 'th';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ArtistController extends Controller
|
||||
@@ -14,7 +17,18 @@ class ArtistController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$artists = Artist::whereHas('artworks')
|
||||
->withCount('artworks')
|
||||
->orderBy('artworks_count', 'desc')
|
||||
->paginate(100);
|
||||
$podcasts = Podcast::where('published', true)->with('episodes')->get();
|
||||
return view('profile.artists', [
|
||||
'user' => $user,
|
||||
'pageTitle' => 'Artists',
|
||||
'podcasts' => $podcasts,
|
||||
'artists' => $artists,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,9 +58,23 @@ class ArtistController extends Controller
|
||||
* @param \App\Models\Artist $artist
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Artist $artist)
|
||||
public function show(Request $request, $slug)
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$artist = Artist::where('slug', $slug)
|
||||
->firstOrFail();
|
||||
$artworks = Artwork::where('artist_id', $artist->id)
|
||||
->with('episode')
|
||||
->with('podcast')
|
||||
->orderBy('artworks.created_at', 'desc')
|
||||
->paginate($perPage = 92, $columns = ['*'], $pageName = 'artworks');
|
||||
$podcasts = Podcast::where('published', true)->with('episodes')->get();
|
||||
return view('profile.artist', [
|
||||
'user' => $user,
|
||||
'artist' => $artist,
|
||||
'artworks' => $artworks,
|
||||
'podcasts' => $podcasts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,18 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rules\File;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use ImageOptimizer;
|
||||
|
||||
class ArtworkController extends Controller
|
||||
{
|
||||
@@ -14,7 +25,19 @@ class ArtworkController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$artworks = Artwork::whereNotNull('approved_by')
|
||||
->with('artist')
|
||||
->orderBy('episode_id', 'desc')
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate($perPage = 3, $columns = ['*'], $pageName = 'artworks');
|
||||
$podcasts = Podcast::where('published', true)->with('episodes')->get();
|
||||
return view('explore.artworks', [
|
||||
'user' => $user,
|
||||
'pageTitle' => 'Explore',
|
||||
'artworks' => $artworks,
|
||||
'podcasts' => $podcasts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +47,13 @@ class ArtworkController extends Controller
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$podcasts = Podcast::where('published', true)->with('episodes')->get();
|
||||
return view('artworks.submit', [
|
||||
'user' => $user,
|
||||
'pageTitle' => 'Submit New Artwork',
|
||||
'podcasts' => $podcasts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,20 +62,79 @@ class ArtworkController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
//
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => ['required', 'max:255',],
|
||||
'podcast' => ['required', 'exists:podcasts,id',],
|
||||
'description' => ['nullable',],
|
||||
'file' => ['required', 'image', Rule::dimensions()->ratio(1)->minWidth(512),],
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
Log::channel('artwork_import')->info('making new artwork model.');
|
||||
$podcast = Podcast::where('id', $request->podcast)->with(['episodes' => function($query) {
|
||||
$query->orderBy('episode_number', 'desc')->limit(1);
|
||||
}])->first();
|
||||
$episode = $podcast->episodes->first();
|
||||
$artist = auth()->user()->artists()->first();
|
||||
$rawFile = $request->file('file');
|
||||
$filename = now()->format('Y')
|
||||
. '/'
|
||||
. now()->format('m')
|
||||
. '/'
|
||||
. Str::slug($artist->name)
|
||||
. '-'
|
||||
. Str::slug($request->title)
|
||||
. '_'
|
||||
. Str::random(8)
|
||||
. '.jpg';
|
||||
$artwork = Artwork::factory()->state([
|
||||
'title' => $request->title,
|
||||
'artist_id' => $artist->id,
|
||||
'description' => $request->description,
|
||||
'overlay_id' => null,
|
||||
'podcast_id' => $podcast->id,
|
||||
'episode_id' => $episode->id,
|
||||
'filename' => $filename,
|
||||
])->create();
|
||||
$img = Image::make($rawFile)->resize(3000, null, function($constraint){
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100)
|
||||
->save(Storage::disk('static')->path('/artworks') . '/' . $artwork->filename);
|
||||
$thumbImg = Image::make($request->file('file'))->resize(512, null, function($constraint){
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100)
|
||||
->save(Storage::disk('static')->path('/thumbnails') . '/' . $artwork->filename);
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path('/artworks/' . $artwork->filename));
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path('/thumbnails/' . $artwork->filename));
|
||||
return redirect('/artworks/' . $artwork->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Models\Artwork $artwork
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param the id of the \App\Models\Artwork $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Artwork $artwork)
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$artwork = Artwork::where('id', $id)
|
||||
->with('podcast')
|
||||
->with('episode')
|
||||
->with('artist')
|
||||
->first();
|
||||
return view('artworks.artwork', [
|
||||
'artwork' => $artwork,
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,4 +170,11 @@ class ArtworkController extends Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function legacyArtLink(Request $request, $any = null)
|
||||
{
|
||||
phpinfo();
|
||||
dd($request->path());
|
||||
//$artwork = Artwork::where('legacy_filename', '/assets/artwork/')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Models\Artist;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Rules;
|
||||
@@ -31,17 +33,24 @@ class RegisteredUserController extends Controller
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'name' => ['unique:artists,name', 'required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'name' => trim($request->name),
|
||||
'email' => trim(strtolower($request->email)),
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
$artist = Artist::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => trim($request->name),
|
||||
'slug' => Str::slug(trim($request->name)),
|
||||
'location' => 'No Agenda Nation',
|
||||
]);
|
||||
|
||||
event(new Registered($user));
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Artworks;
|
||||
use App\Models\Episode;
|
||||
|
||||
class EpisodeController extends Controller
|
||||
{
|
||||
@@ -44,9 +48,26 @@ class EpisodeController extends Controller
|
||||
* @param \App\Models\Episode $episode
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Episode $episode)
|
||||
public function show(Request $request, $podcast_slug, $slug)
|
||||
{
|
||||
//
|
||||
$user = auth()->user();
|
||||
$episode = Episode::where('slug', $slug)
|
||||
->with('artworks')
|
||||
->with('artwork')
|
||||
->with('podcast')
|
||||
->firstOrFail();
|
||||
$podcasts = Podcast::where('published', true)->with('episodes', function ($query) {
|
||||
$query->orderBy('episode_number', 'desc');
|
||||
$query->where('published', true);
|
||||
$query->take(10);
|
||||
})->get();
|
||||
return view('episodes.episode', [
|
||||
'user' => $user,
|
||||
'pageTitle' => '"' . $episode->title . '" ' . $episode->podcast->name . ' Episode ' . number_format($episode->episode_number + 0),
|
||||
'podcast' => $episode->podcast,
|
||||
'episode' => $episode,
|
||||
'podcasts' => $podcasts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
144
site/app/Http/Controllers/PageController.php
Normal file
144
site/app/Http/Controllers/PageController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Episode;
|
||||
|
||||
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function landing(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$headerCounters = $this->getHeaderCounters();
|
||||
$recentEpisodes = $this->mostRecentEpisodes();
|
||||
$recentSubmissions = $this->mostRecentSubmissions();
|
||||
$leaderboard = $this->leaderboardTwelveMonths();
|
||||
|
||||
return view('home.page', [
|
||||
'user' => $user,
|
||||
'pageTitle' => 'Home',
|
||||
'headerCounters' => $headerCounters,
|
||||
'recentEpisodes' => $recentEpisodes,
|
||||
'recentSubmissions' => $recentSubmissions,
|
||||
'leaderboard' => $leaderboard,
|
||||
'preferredTheme' => $request->session()->get('preferred_theme') ?? 'dark',
|
||||
]);
|
||||
}
|
||||
|
||||
private function mostRecentSubmissions() {
|
||||
$artworks = Cache::remember('latestSubmissions', 30, function() {
|
||||
return Artwork::whereNotNull('approved_by')
|
||||
->with('artist')
|
||||
->with('episode')
|
||||
->with('podcast')
|
||||
->orderBy('created_at', 'desc')
|
||||
->limit(50)
|
||||
->get();
|
||||
});
|
||||
return $artworks;
|
||||
}
|
||||
|
||||
private function mostRecentEpisodes()
|
||||
{
|
||||
$episodes = Cache::remember('latestEpisodes', 30, function() {
|
||||
return Episode::where('published', true)
|
||||
->whereHas('artwork')
|
||||
->with('podcast')
|
||||
->with('artwork')
|
||||
->with('artwork.artist')
|
||||
->orderBy('episode_date', 'desc')
|
||||
->limit(10)
|
||||
->get();
|
||||
});
|
||||
return $episodes;
|
||||
}
|
||||
|
||||
private function getHeaderCounters()
|
||||
{
|
||||
$headerCounters = [];
|
||||
$artworkCountNumber = Cache::remember('artworkCountNumber', 10, function() {
|
||||
return Artwork::all()->count();
|
||||
});
|
||||
$artistCountNumber = Cache::remember('artistCountNumber', 10, function() {
|
||||
return Artist::all()->count();
|
||||
});
|
||||
$episodeCountNumber = Cache::remember('episodeCountNumber', 10, function() {
|
||||
return Episode::all()->count();
|
||||
});
|
||||
$headerCounters['Artworks'] = $this->shortNumberCount($artworkCountNumber);
|
||||
$headerCounters['Artists'] = $this->shortNumberCount($artistCountNumber);
|
||||
$headerCounters['Episodes'] = $this->shortNumberCount($episodeCountNumber);
|
||||
return $headerCounters;
|
||||
}
|
||||
private function shortNumberCount($number)
|
||||
{
|
||||
$units = ['', 'K', 'M', 'B', 'T'];
|
||||
for ($i = 0; $number >= 1000; $i++) {
|
||||
$number /= 1000;
|
||||
}
|
||||
return [
|
||||
'number' => $this->numberFormatPrecision($number, 1), //number_format(floatval($number), 1),
|
||||
'unit' => $units[$i],
|
||||
];
|
||||
}
|
||||
|
||||
private function numberFormatPrecision($number, $precision = 2, $separator = '.')
|
||||
{
|
||||
$numberParts = explode($separator, $number);
|
||||
$response = $numberParts[0];
|
||||
if (count($numberParts)>1 && $precision > 0) {
|
||||
$response .= $separator;
|
||||
$response .= substr($numberParts[1], 0, $precision);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function leaderboardTwelveMonths() {
|
||||
$endDate = now()->endOfDay()->subYear()->format('Y-m-d');
|
||||
$leaderboard = DB::table('episodes')
|
||||
->join('artworks', 'artworks.id', '=', 'episodes.artwork_id')
|
||||
->join('artists', 'artists.id', '=', 'artworks.artist_id')
|
||||
->select([
|
||||
DB::raw('artists.id as artistId'),
|
||||
DB::raw('artists.name as artistName'),
|
||||
DB::raw('count(artworks.id) as artworkCount')
|
||||
])
|
||||
->where('episodes.published', 1)
|
||||
->where('episodes.episode_date', '>=', $endDate)
|
||||
->groupBy('artistId')
|
||||
->orderByDesc('artworkCount')
|
||||
->limit(10)
|
||||
->get();
|
||||
$leaderboard = $this->addArtistModelToLeaderboard($leaderboard);
|
||||
return $leaderboard;
|
||||
}
|
||||
|
||||
private function addArtistModelToLeaderboard($leaderboard) {
|
||||
$artistIds = [];
|
||||
foreach ($leaderboard as $lb) {
|
||||
$artistIds[] = $lb->artistId;
|
||||
}
|
||||
$artists = Artist::whereIn('id', $artistIds)->get();
|
||||
foreach ($leaderboard as $lb) {
|
||||
$lb->artist = $artists->where('id', $lb->artistId)->first();
|
||||
}
|
||||
$p = 0;
|
||||
foreach ($leaderboard as $lb) {
|
||||
$p++;
|
||||
$lb->position = $p;
|
||||
}
|
||||
return $leaderboard;
|
||||
}
|
||||
|
||||
public function setSessionTheme(Request $request) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,8 +3,34 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Artworks;
|
||||
use App\Models\Episode;
|
||||
|
||||
|
||||
class PodcastController extends Controller
|
||||
{
|
||||
//
|
||||
public function show(Request $request, $slug)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$podcast = Podcast::where('slug', $slug)
|
||||
->where('published', true)
|
||||
->firstOrFail();
|
||||
$episodes = Episode::where('published', true)
|
||||
->whereNotNull('artwork_id')
|
||||
->with('artwork')
|
||||
->with('artworks')
|
||||
->where('podcast_id', $podcast->id)
|
||||
->orderBy('episode_number', 'desc')->paginate(100);
|
||||
$podcasts = Podcast::where('published', true)->with('episodes')->get();
|
||||
return view('podcasts.podcast', [
|
||||
'user' => $user,
|
||||
'pageTitle' => $podcast->name,
|
||||
'podcast' => $podcast,
|
||||
'episodes' => $episodes,
|
||||
'podcasts' => $podcasts,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class Kernel extends HttpKernel
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
68
site/app/Jobs/ImportLegacyUserJob.php
Normal file
68
site/app/Jobs/ImportLegacyUserJob.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use App\Models\User;
|
||||
use App\Models\Artist;
|
||||
use Carbon\Carbon;
|
||||
use App\Jobs\StashAndOptimizeLegacyArtworkJob;
|
||||
|
||||
class ImportLegacyUserJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$name = str_replace(' ', '', $this->user->username);
|
||||
$email = strtolower(trim($this->user->email));
|
||||
$email_verified_at = Carbon::parse($this->user->created_at);
|
||||
$this->createUser($name, $email, $email_verified_at);
|
||||
}
|
||||
|
||||
private function createUser($name, $email, $email_verified_at)
|
||||
{
|
||||
$user = User::where('name', $name)->first();
|
||||
if (!$user) {
|
||||
$user = User::factory()->state([
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'email_verified_at' => $email_verified_at,
|
||||
'remember_token' => null,
|
||||
])->create();
|
||||
}
|
||||
$artist = Artist::where('user_id', $user->id)->first();
|
||||
if (!$artist) {
|
||||
$artist = Artist::factory()->state([
|
||||
'user_id' => $user->id,
|
||||
'name' => $this->user->profile->name,
|
||||
'avatar' => null,
|
||||
'header' => null,
|
||||
'location' => $this->user->profile->location ?? 'No Agenda Art Generator',
|
||||
'website' => $this->user->profile->website ?? null,
|
||||
'bio' => null,
|
||||
])->create();
|
||||
}
|
||||
foreach ($this->user->artworks as $artwork) {
|
||||
StashAndOptimizeLegacyArtworkJob::dispatch($artist, $artwork);
|
||||
}
|
||||
}
|
||||
}
|
||||
125
site/app/Jobs/StashAndOptimizeLegacyArtworkJob.php
Normal file
125
site/app/Jobs/StashAndOptimizeLegacyArtworkJob.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use App\Models\User;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Intervention\Image\Facades\Image;
|
||||
use Carbon\Carbon;
|
||||
use ImageOptimizer;
|
||||
|
||||
class StashAndOptimizeLegacyArtworkJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $artist;
|
||||
|
||||
protected $artwork;
|
||||
|
||||
public $tries = 2;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($artist, $artwork)
|
||||
{
|
||||
$this->artist = $artist;
|
||||
$this->artwork = $artwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$date = Carbon::parse($this->artwork->created_at);
|
||||
$basename = $date->format('Y')
|
||||
. '/' . $date->format('m')
|
||||
. '/' . Str::slug($this->artist->name)
|
||||
. '-' . Str::slug($this->artwork->title)
|
||||
. '_' . $this->artwork->id . '.jpg';
|
||||
$filename = 'artworks/' . $basename;
|
||||
$thumbnailName = 'thumbnails/' . $basename;
|
||||
if (Storage::disk('static')->exists($filename)) {
|
||||
Log::channel('artwork_import')->error($filename . ' already exists. Filesize: ' . Storage::disk('static')->size($filename));
|
||||
$this->createArtwork($basename);
|
||||
return;
|
||||
}
|
||||
$img = Image::make('/legacypublic' . $this->artwork->path . '/' . $this->artwork->filename)
|
||||
->resize(3000, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100);
|
||||
$thumbImg = Image::make('/legacypublic' . $this->artwork->path . '/' . $this->artwork->filename)
|
||||
->resize(512, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
})
|
||||
->encode('jpg', 100);
|
||||
$imgLocation = Storage::disk('static')->put($filename, $img);
|
||||
$thumbLocation = Storage::disk('static')->put($thumbnailName, $thumbImg);
|
||||
$size_before = Storage::disk('static')->size($filename);
|
||||
$thumb_size_before = Storage::disk('static')->size($thumbnailName);
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path($filename));
|
||||
ImageOptimizer::optimize(Storage::disk('static')->path($thumbnailName));
|
||||
$size_after = Storage::disk('static')->size($filename);
|
||||
$thumb_size_after = Storage::disk('static')->size($thumbnailName);
|
||||
$diff = $size_before - $size_after;
|
||||
$thumbDiff = $thumb_size_before - $thumb_size_after;
|
||||
Log::channel('artwork_import')->info('Filesize Before: ' . $size_before);
|
||||
Log::channel('artwork_import')->info('Filesize After: ' . $size_after);
|
||||
$perc_smaller = ($diff / $size_before) * 100;
|
||||
$thumb_perc_smaller = ($thumbDiff / $thumb_size_before) * 100;
|
||||
Log::channel('artwork_import')->info(number_format($perc_smaller, 2) . '% smaller.');
|
||||
Log::channel('artwork_import')->info(number_format($thumb_perc_smaller, 2) . '% smaller thumbnail - ' . $thumb_size_after);
|
||||
Log::channel('artwork_import')->info('Saved and resized ' . $filename);
|
||||
$this->createArtwork($basename);
|
||||
}
|
||||
|
||||
private function createArtwork($basename) {
|
||||
$artwork = Artwork::where('legacy_id', $this->artwork->id)->first();
|
||||
if (!$this->artwork->episode_id) {
|
||||
$episode = Episode::where('episode_date', '>=', Carbon::parse($this->artwork->created_at)->startOfDay())
|
||||
->orderBy('episode_date', 'asc')
|
||||
->first();
|
||||
} else {
|
||||
$episode = Episode::where('legacy_id', $this->artwork->episode_id)->first();
|
||||
}
|
||||
if (!$artwork) {
|
||||
$artwork = Artwork::where('filename', $basename)->first();
|
||||
if ($artwork) {
|
||||
$artwork->legacy_id = $this->artwork->id;
|
||||
$artwork->episode_id = $episode->id ?? null;
|
||||
$artwork->save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!$artwork) {
|
||||
Log::channel('artwork_import')->info('making new artwork model for ' . $basename);
|
||||
Artwork::factory()->state([
|
||||
'title' => $this->artwork->title,
|
||||
'artist_id' => $this->artist->id,
|
||||
'description' => '',
|
||||
'podcast_id' => 1,
|
||||
'overlay_id' => $this->artwork->overlay_id,
|
||||
'episode_id' => $episode->id ?? null,
|
||||
'filename' => $basename ?? null,
|
||||
'created_at' => Carbon::parse($this->artwork->created_at),
|
||||
'updated_at' => Carbon::parse($this->artwork->updated_at),
|
||||
'legacy_id' => $this->artwork->id,
|
||||
])->create();
|
||||
} else {
|
||||
Log::channel('artwork_import')->info($artwork->id . ' has a model it exists with ' . $artwork->filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
site/app/Livewire/Counter.php
Normal file
25
site/app/Livewire/Counter.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class Counter extends Component
|
||||
{
|
||||
public $count = 1;
|
||||
|
||||
public function increment()
|
||||
{
|
||||
$this->count++;
|
||||
}
|
||||
|
||||
public function decrement()
|
||||
{
|
||||
$this->count--;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.counter');
|
||||
}
|
||||
}
|
||||
24
site/app/Livewire/Themeswitch.php
Normal file
24
site/app/Livewire/Themeswitch.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class Themeswitch extends Component
|
||||
{
|
||||
|
||||
public function light()
|
||||
{
|
||||
session()->put('preferred_theme', 'light');
|
||||
}
|
||||
|
||||
public function dark()
|
||||
{
|
||||
session()->put('preferred_theme', 'dark');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.themeswitch');
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,29 @@ class Artist extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'name',
|
||||
'slug',
|
||||
'avatar',
|
||||
'header',
|
||||
'location',
|
||||
'website',
|
||||
'bio',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongs_to(User::class);
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function artworks()
|
||||
|
||||
@@ -16,6 +16,12 @@ class Artwork extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function podcast()
|
||||
{
|
||||
return $this->belongsTo(Podcast::class);
|
||||
|
||||
@@ -14,6 +14,13 @@ class Episode extends Model
|
||||
|
||||
protected $dates = ['episode_date', 'created_at', 'updated_at', 'deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'episode_date' => 'date',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function podcast()
|
||||
{
|
||||
return $this->belongsTo(Podcast::class);
|
||||
@@ -21,7 +28,12 @@ class Episode extends Model
|
||||
|
||||
public function artwork()
|
||||
{
|
||||
return $this->hasOne(Artwork::class);
|
||||
return $this->hasOne(Artwork::class, 'id', 'artwork_id');
|
||||
}
|
||||
|
||||
public function artworks()
|
||||
{
|
||||
return $this->hasMany(Artwork::class);
|
||||
}
|
||||
|
||||
public function artist()
|
||||
|
||||
@@ -16,6 +16,12 @@ class Overlay extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function artist()
|
||||
{
|
||||
return $this->belongsTo(Artist::class);
|
||||
|
||||
@@ -16,6 +16,13 @@ class Podcast extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'deleted_at', 'added_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
'added_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function episodes()
|
||||
{
|
||||
return $this->hasMany(Episode::class);
|
||||
|
||||
@@ -14,8 +14,6 @@ class User extends Authenticatable
|
||||
|
||||
protected $table = 'users';
|
||||
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
@@ -44,6 +42,17 @@ class User extends Authenticatable
|
||||
*/
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be appended.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $appends = [
|
||||
|
||||
];
|
||||
|
||||
public function artists()
|
||||
|
||||
@@ -13,6 +13,11 @@ class Wallet extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function walletType()
|
||||
{
|
||||
return $this->hasOne(WalletType::class);
|
||||
|
||||
@@ -13,6 +13,11 @@ class WalletType extends Model
|
||||
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function wallets()
|
||||
{
|
||||
return $this->hasMany(Wallet::class);
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use App\Models\Podcast;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,6 +22,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Paginator::useBootstrapFive();
|
||||
$publishedPodcasts = Podcast::where('published', true)->select(['name', 'slug'])->get();
|
||||
View::share(['navPodcasts' => $publishedPodcasts]);
|
||||
}
|
||||
}
|
||||
|
||||
58
site/app/Providers/Filament/AdminPanelProvider.php
Normal file
58
site/app/Providers/Filament/AdminPanelProvider.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers\Filament;
|
||||
|
||||
use Filament\Http\Middleware\Authenticate;
|
||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||
use Filament\Pages;
|
||||
use Filament\Panel;
|
||||
use Filament\PanelProvider;
|
||||
use Filament\Support\Colors\Color;
|
||||
use Filament\Widgets;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
|
||||
class AdminPanelProvider extends PanelProvider
|
||||
{
|
||||
public function panel(Panel $panel): Panel
|
||||
{
|
||||
return $panel
|
||||
->default()
|
||||
->id('admin')
|
||||
->path('admin')
|
||||
->login()
|
||||
->colors([
|
||||
'primary' => Color::Amber,
|
||||
])
|
||||
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
|
||||
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
|
||||
->pages([
|
||||
Pages\Dashboard::class,
|
||||
])
|
||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
||||
->widgets([
|
||||
Widgets\AccountWidget::class,
|
||||
Widgets\FilamentInfoWidget::class,
|
||||
])
|
||||
->middleware([
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
AuthenticateSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
DisableBladeIconComponents::class,
|
||||
DispatchServingFilamentEvent::class,
|
||||
])
|
||||
->authMiddleware([
|
||||
Authenticate::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const HOME = '/dashboard';
|
||||
public const HOME = '/';
|
||||
|
||||
/**
|
||||
* Define your route model bindings, pattern filters, and other route configuration.
|
||||
|
||||
@@ -2,16 +2,24 @@
|
||||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
"keywords": ["laravel", "framework"],
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"framework"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"andreiio/blade-remix-icon": "^2.6",
|
||||
"blade-ui-kit/blade-icons": "^1.5",
|
||||
"filament/filament": "^3.0-stable",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"intervention/image": "^2.7",
|
||||
"laravel/framework": "^10.10",
|
||||
"laravel/sanctum": "^3.2",
|
||||
"laravel/sanctum": "^3.3",
|
||||
"laravel/tinker": "^2.8",
|
||||
"livewire/livewire": "^2.12"
|
||||
"livewire/livewire": "^3.2",
|
||||
"mckenziearts/blade-untitledui-icons": "^1.2",
|
||||
"spatie/laravel-image-optimizer": "^1.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
@@ -28,7 +36,10 @@
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"app/Helpers/pcagHelpers.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@@ -38,7 +49,8 @@
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
"@php artisan package:discover --ansi",
|
||||
"@php artisan filament:upgrade"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
|
||||
3361
site/composer.lock
generated
3361
site/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,8 @@ return [
|
||||
|
||||
'asset_url' => env('ASSET_URL'),
|
||||
|
||||
'static_asset_url' => env('STATIC_ASSET_URL'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
@@ -167,6 +169,7 @@ return [
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
// App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\Filament\AdminPanelProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
])->toArray(),
|
||||
|
||||
|
||||
183
site/config/blade-icons.php
Normal file
183
site/config/blade-icons.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Icons Sets
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| With this config option you can define a couple of
|
||||
| default icon sets. Provide a key name for your icon
|
||||
| set and a combination from the options below.
|
||||
|
|
||||
*/
|
||||
|
||||
'sets' => [
|
||||
|
||||
// 'default' => [
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Icons Path
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | Provide the relative path from your app root to your SVG icons
|
||||
// | directory. Icons are loaded recursively so there's no need to
|
||||
// | list every sub-directory.
|
||||
// |
|
||||
// | Relative to the disk root when the disk option is set.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'path' => 'resources/svg',
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Filesystem Disk
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | Optionally, provide a specific filesystem disk to read
|
||||
// | icons from. When defining a disk, the "path" option
|
||||
// | starts relatively from the disk root.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'disk' => '',
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Default Prefix
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | This config option allows you to define a default prefix for
|
||||
// | your icons. The dash separator will be applied automatically
|
||||
// | to every icon name. It's required and needs to be unique.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'prefix' => 'icon',
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Fallback Icon
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | This config option allows you to define a fallback
|
||||
// | icon when an icon in this set cannot be found.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'fallback' => '',
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Default Set Classes
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | This config option allows you to define some classes which
|
||||
// | will be applied by default to all icons within this set.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'class' => '',
|
||||
//
|
||||
// /*
|
||||
// |-----------------------------------------------------------------
|
||||
// | Default Set Attributes
|
||||
// |-----------------------------------------------------------------
|
||||
// |
|
||||
// | This config option allows you to define some attributes which
|
||||
// | will be applied by default to all icons within this set.
|
||||
// |
|
||||
// */
|
||||
//
|
||||
// 'attributes' => [
|
||||
// // 'width' => 50,
|
||||
// // 'height' => 50,
|
||||
// ],
|
||||
//
|
||||
// ],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Default Classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This config option allows you to define some classes which
|
||||
| will be applied by default to all icons.
|
||||
|
|
||||
*/
|
||||
|
||||
'class' => '',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Default Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This config option allows you to define some attributes which
|
||||
| will be applied by default to all icons.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [
|
||||
// 'width' => 50,
|
||||
// 'height' => 50,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Fallback Icon
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This config option allows you to define a global fallback
|
||||
| icon when an icon in any set cannot be found. It can
|
||||
| reference any icon from any configured set.
|
||||
|
|
||||
*/
|
||||
|
||||
'fallback' => '',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Components
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These config options allow you to define some
|
||||
| settings related to Blade Components.
|
||||
|
|
||||
*/
|
||||
|
||||
'components' => [
|
||||
|
||||
/*
|
||||
|----------------------------------------------------------------------
|
||||
| Disable Components
|
||||
|----------------------------------------------------------------------
|
||||
|
|
||||
| This config option allows you to disable Blade components
|
||||
| completely. It's useful to avoid performance problems
|
||||
| when working with large icon libraries.
|
||||
|
|
||||
*/
|
||||
|
||||
'disabled' => false,
|
||||
|
||||
/*
|
||||
|----------------------------------------------------------------------
|
||||
| Default Icon Component Name
|
||||
|----------------------------------------------------------------------
|
||||
|
|
||||
| This config option allows you to define the name
|
||||
| for the default Icon class component.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => 'icon',
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -56,6 +56,26 @@ return [
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'legacy' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('LEGACY_DATABASE_URL'),
|
||||
'host' => env('LEGACY_DB_HOST', '127.0.0.1'),
|
||||
'port' => env('LEGACY_DB_PORT', '3306'),
|
||||
'database' => env('LEGACY_DB_DATABASE', 'forge'),
|
||||
'username' => env('LEGACY_DB_USERNAME', 'forge'),
|
||||
'password' => env('LEGACY_DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
@@ -148,4 +168,4 @@ return [
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
];
|
||||
66
site/config/image-optimizer.php
Normal file
66
site/config/image-optimizer.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use Spatie\ImageOptimizer\Optimizers\Cwebp;
|
||||
use Spatie\ImageOptimizer\Optimizers\Gifsicle;
|
||||
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
|
||||
use Spatie\ImageOptimizer\Optimizers\Optipng;
|
||||
use Spatie\ImageOptimizer\Optimizers\Pngquant;
|
||||
use Spatie\ImageOptimizer\Optimizers\Svgo;
|
||||
|
||||
return [
|
||||
/*
|
||||
* When calling `optimize` the package will automatically determine which optimizers
|
||||
* should run for the given image.
|
||||
*/
|
||||
'optimizers' => [
|
||||
|
||||
Jpegoptim::class => [
|
||||
'-m72', // set maximum quality to 85%
|
||||
'--strip-all', // this strips out all text information such as comments and EXIF data
|
||||
'--all-progressive', // this will make sure the resulting image is a progressive one
|
||||
],
|
||||
|
||||
Pngquant::class => [
|
||||
'--force', // required parameter for this package
|
||||
],
|
||||
|
||||
Optipng::class => [
|
||||
'-i0', // this will result in a non-interlaced, progressive scanned image
|
||||
'-o2', // this set the optimization level to two (multiple IDAT compression trials)
|
||||
'-quiet', // required parameter for this package
|
||||
],
|
||||
|
||||
Svgo::class => [
|
||||
'--disable=cleanupIDs', // disabling because it is know to cause troubles
|
||||
],
|
||||
|
||||
Gifsicle::class => [
|
||||
'-b', // required parameter for this package
|
||||
'-O3', // this produces the slowest but best results
|
||||
],
|
||||
|
||||
Cwebp::class => [
|
||||
'-m 6', // for the slowest compression method in order to get the best compression.
|
||||
'-pass 10', // for maximizing the amount of analysis pass.
|
||||
'-mt', // multithreading for some speed improvements.
|
||||
'-q 90', // quality factor that brings the least noticeable changes.
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
* The directory where your binaries are stored.
|
||||
* Only use this when you binaries are not accessible in the global environment.
|
||||
*/
|
||||
'binary_path' => '',
|
||||
|
||||
/*
|
||||
* The maximum time in seconds each optimizer is allowed to run separately.
|
||||
*/
|
||||
'timeout' => 60,
|
||||
|
||||
/*
|
||||
* If set to `true` all output of the optimizer binaries will be appended to the default log.
|
||||
* You can also set this to a class that implements `Psr\Log\LoggerInterface`.
|
||||
*/
|
||||
'log_optimizer_activity' => false,
|
||||
];
|
||||
@@ -65,6 +65,13 @@ return [
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'artwork_import' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/artwork_import.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
|
||||
@@ -2,10 +2,20 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Artist;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Str;
|
||||
|
||||
class ArtistFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Artist::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -13,8 +23,17 @@ class ArtistFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$name = fake()->name();
|
||||
$slug = Str::slug(strtolower(trim($name)));
|
||||
return [
|
||||
//
|
||||
'user_id' => User::factory(),
|
||||
'name' => $name,
|
||||
'slug' => $slug,
|
||||
'avatar' => fake()->imageUrl(512, 512),
|
||||
'header' => fake()->imageUrl(270, 185),
|
||||
'location' => fake()->city() . ', ' . fake()->state(),
|
||||
'website' => rand(0, 1) ? fake()->url : null,
|
||||
'bio' => fake()->paragraphs(rand(1, 3), true),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,23 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
|
||||
class ArtworkFactory extends Factory
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Artwork::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -13,8 +27,19 @@ class ArtworkFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$created = fake()->dateTimeThisDecade();
|
||||
return [
|
||||
//
|
||||
'title' => fake()->name(),
|
||||
'description' => rand(0, 1) ? fake()->paragraphs(rand(1, 3), true) : null,
|
||||
'artist_id' => Artist::factory(),
|
||||
'podcast_id' => Podcast::factory(),
|
||||
'episode_id' => Episode::factory(),
|
||||
'overlay_id' => rand(0, 1) ? Overlay::factory() : null,
|
||||
'filename' => fake()->imageUrl(3000, 3000),
|
||||
'created_at' => $created,
|
||||
'updated_at' => $created,
|
||||
'legacy_id' => null,
|
||||
'approved_by' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,24 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EpisodeFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Episode::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -13,8 +27,20 @@ class EpisodeFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$title = fake()->name();
|
||||
$slug = Str::slug($title);
|
||||
$created = fake()->dateTimeThisDecade();
|
||||
return [
|
||||
//
|
||||
'podcast_id' => Podcast::factory(),
|
||||
'artwork_id' => Artwork::factory(),
|
||||
'published' => fake()->boolean(),
|
||||
'episode_date' => fake()->dateTimeThisDecade(),
|
||||
'slug' => $slug,
|
||||
'title' => $title,
|
||||
'mp3' => fake()->url(),
|
||||
'created_at' => $created,
|
||||
'updated_at' => $created,
|
||||
'legacy_id' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,24 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
|
||||
|
||||
class OverlayFactory extends Factory
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Overlay::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -13,8 +28,14 @@ class OverlayFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$name = fake()->name();
|
||||
$slug = Str::slug($name);
|
||||
return [
|
||||
//
|
||||
'name' => $name,
|
||||
'artist_id' => Artist::factory(),
|
||||
'podcast_id' => Podcast::factory(),
|
||||
'available' => fake()->boolean(),
|
||||
'filename' => fake()->imageUrl(3000, 3000),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,21 @@ namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
|
||||
class PodcastFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Podcast::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -14,12 +26,14 @@ class PodcastFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$name = fake()->name();
|
||||
$slug = Str::slug($name);
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'name' => $name,
|
||||
'description' => fake()->paragraphs(rand(1,3), true),
|
||||
'website' => 'https://' . fake()->domainName(),
|
||||
'feed' => fake()->url(),
|
||||
'slug' => fake()->slug(),
|
||||
'feed' => 'podcast/' . $slug,
|
||||
'slug' => $slug,
|
||||
'published' => fake()->boolean(),
|
||||
'added_at' => fake()->dateTimeThisDecade(),
|
||||
];
|
||||
|
||||
@@ -4,9 +4,23 @@ namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
use App\Models\User;
|
||||
|
||||
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = User::class;
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
@@ -14,12 +28,14 @@ class UserFactory extends Factory
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
$password = Hash::make(Str::random(rand(8, 16)));
|
||||
return [
|
||||
'name' => $this->faker->name(),
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'password' => $password,
|
||||
'remember_token' => Str::random(10),
|
||||
'legacy_id' => null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Models\User;
|
||||
|
||||
class CreateArtistsTable extends Migration
|
||||
{
|
||||
@@ -15,7 +16,10 @@ class CreateArtistsTable extends Migration
|
||||
{
|
||||
Schema::create('artists', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained();
|
||||
$table->foreignIdFor(User::class)
|
||||
->constrained()
|
||||
->cascadeOnUpdate()
|
||||
->cascadeOnDelete();
|
||||
$table->string('name')->unique();
|
||||
$table->string('avatar')->nullable();
|
||||
$table->string('header')->nullable();
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('episodes', function (Blueprint $table) {
|
||||
$table->decimal('episode_number', 8, 1)->after('episode_date')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('episodes', function (Blueprint $table) {
|
||||
$table->dropColumn('episode_number');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('artworks', function (Blueprint $table) {
|
||||
$table->bigInteger('legacy_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('artworks', function (Blueprint $table) {
|
||||
$table->dropColumn('legacy_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('episodes', function (Blueprint $table) {
|
||||
$table->bigInteger('legacy_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('episodes', function (Blueprint $table) {
|
||||
$table->dropColumn('legacy_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('artworks', function (Blueprint $table) {
|
||||
$table->bigInteger('approved_by')->nullable()->after('filename');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('artworks', function (Blueprint $table) {
|
||||
$table->dropColumn('approved_by');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('users', function (Blueprint $table) {
|
||||
$table->integer('legacy_id')->nullable()->unsigned();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('legacy_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('artworks', function (Blueprint $table) {
|
||||
$table->string('legacy_filename')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('artworks', function (Blueprint $table) {
|
||||
$table->dropColumn('legacy_filename');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('users', function (Blueprint $table) {
|
||||
$table->string('theme')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('theme');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('artists', function (Blueprint $table) {
|
||||
$table->string('slug')->after('name');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('artists', function (Blueprint $table) {
|
||||
$table->dropColumn('slug');
|
||||
});
|
||||
}
|
||||
};
|
||||
60
site/database/seeders/EpisodeSeeder.php
Normal file
60
site/database/seeders/EpisodeSeeder.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class EpisodeSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$current_page = 1;
|
||||
$response = $this->getResponseFromApi($current_page);
|
||||
$last_page = $response->object()->last_page;
|
||||
$this->command->info('Last Page: ' . $last_page);
|
||||
$podcast = Podcast::find(1);
|
||||
while ($current_page <= $last_page) {
|
||||
$this->command->info('Getting Page ' . $current_page);
|
||||
foreach ($response->object()->data as $episode) {
|
||||
$podcastEpisode = Episode::where('title', $episode->title)->first();
|
||||
if (!$podcastEpisode) {
|
||||
$podcastEpisode = Episode::factory()->state([
|
||||
'podcast_id' => 1,
|
||||
'episode_date' => Carbon::parse($episode->show_date),
|
||||
'published' => (bool)$episode->published,
|
||||
'artwork_id' => null,
|
||||
'slug' => $episode->episode_number . '_' . Str::slug($episode->title),
|
||||
'title' => $episode->title,
|
||||
'mp3' => $episode->link,
|
||||
'created_at' => Carbon::parse($episode->created_at),
|
||||
'updated_at' => Carbon::parse($episode->updated_at),
|
||||
'legacy_id' => $episode->id ?? null
|
||||
])->create();
|
||||
} else {
|
||||
$podcastEpisode->legacy_id = $episode->id ?? null;
|
||||
if ($podcastEpisode->isDirty()) {
|
||||
$podcastEpisode->save();
|
||||
}
|
||||
}
|
||||
$this->command->info('Created ' . $episode->show_date . ' - (' . $episode->episode_number . ') ' . $episode->title);
|
||||
}
|
||||
$current_page++;
|
||||
$response = $this->getResponseFromApi($current_page);
|
||||
}
|
||||
}
|
||||
|
||||
private function getResponseFromApi($current_page) {
|
||||
$response = Http::timeout(180)
|
||||
->get('https://noagendaartgenerator.com/episodesjson?p=7476&page=' . $current_page);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
31
site/database/seeders/FixLegacyEpisodeSeeder.php
Normal file
31
site/database/seeders/FixLegacyEpisodeSeeder.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Artwork;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facade\Log;
|
||||
|
||||
class FixLegacyEpisodeSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$episodes = Episode::all();
|
||||
foreach ($episodes as $episode) {
|
||||
if (is_null($episode->episode_number) || $episode->episode_number == 0) {
|
||||
$ep_num_arr = explode('_', $episode->slug);
|
||||
$episode->episode_number = $ep_num_arr[0];
|
||||
}
|
||||
if ($episode->isDirty()) {
|
||||
$episode->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
site/database/seeders/MapLegacyIdsSeeder.php
Normal file
17
site/database/seeders/MapLegacyIdsSeeder.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class MapLegacyIdsSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,31 @@ class PodcastSeeder extends Seeder
|
||||
$feed = 'https://hogstory.net/feed/podcast';
|
||||
$added = '2019-02-22 20:00:00';
|
||||
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||
|
||||
|
||||
$name = 'Rare Encounter';
|
||||
$description = 'AbleKirby and coldacid converse on anime they watch, books and manga they read, games they play,
|
||||
and all the tech stuff that they come across.';
|
||||
$website = 'http://rareencounter.net';
|
||||
$slug = 'rare-encounter';
|
||||
$feed = 'https://rareencounter.net/external.php?name=RSS';
|
||||
$added = '2020-07-16 20:00:00';
|
||||
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||
|
||||
$name = 'Unrelenting';
|
||||
$description = 'The Unrelenting Podcast is hosted by Gene Naftulvev and Darren O’Neill. It covers politics, technology, pop-culture, and more!';
|
||||
$website = 'http://unrelenting.show';
|
||||
$slug = 'unrelenting';
|
||||
$feed = 'https://www.unrelenting.show/feed/podcast/';
|
||||
$added = '2021-10-29 20:00:00';
|
||||
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||
|
||||
$name = 'The Boostagram Ball';
|
||||
$description = 'The First Podcast with Value4Value Music hosted by Adam Curry';
|
||||
$website = 'https://boostagramball.com';
|
||||
$slug = 'boostagram-ball';
|
||||
$feed = 'https://mp3s.nashownotes.com/bballrss.xml';
|
||||
$added = '2023-07-29 20:00:00';
|
||||
$this->createPodcast($name, $description, $website, $slug, $feed, $added);
|
||||
}
|
||||
|
||||
private function createPodcast($name, $description, $website, $slug, $feed, $added) {
|
||||
|
||||
105
site/database/seeders/SeedFromOldApiSeeder.php
Normal file
105
site/database/seeders/SeedFromOldApiSeeder.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Episode;
|
||||
use App\Models\Podcast;
|
||||
use App\Models\Overlay;
|
||||
use App\Jobs\StashAndOptimizeLegacyArtworkJob;
|
||||
use App\Jobs\ImportLegacyUserJob;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SeedFromOldApiSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//$this->populateLegacyArtworks();
|
||||
//die();
|
||||
$current_page = 0;
|
||||
$totalArtworks = 0;
|
||||
$missingArtworks = 0;
|
||||
$missingModel = 0;
|
||||
$response = $this->getResponseFromApi($current_page);
|
||||
$last_page = $response->object()->users->last_page;
|
||||
while ($current_page <= $last_page) {
|
||||
$this->command->info('Getting Page ' . $current_page);
|
||||
foreach ($response->object()->users->data as $user) {
|
||||
$this->command->line('Getting Art for ' . $user->profile->name . ', found ' . count($user->artworks) . ' artworks.');
|
||||
$totalArtworks += count($user->artworks);
|
||||
$legacyUser = Artist::where('name', $user->profile->name)->first();
|
||||
if (!$legacyUser) {
|
||||
ImportLegacyUserJob::dispatch($user);
|
||||
} else {
|
||||
if ($legacyUser->artworks->count() < count($user->artworks)) {
|
||||
$countDiff = count($user->artworks) - $legacyUser->artworks->count();
|
||||
$missingArtworks += $countDiff;
|
||||
$this->command->comment('Artist ID '
|
||||
. $legacyUser->id
|
||||
. ' '
|
||||
. $legacyUser->name
|
||||
. ' has '
|
||||
. $legacyUser->artworks->count()
|
||||
. ' artworks.');
|
||||
$this->command->error('Missing ' . $countDiff . ' artworks.');
|
||||
foreach ($user->artworks as $artwork) {
|
||||
$date = Carbon::parse($artwork->created_at);
|
||||
$basename = $date->format('Y')
|
||||
. '/' . $date->format('m')
|
||||
. '/' . Str::slug($legacyUser->name)
|
||||
. '-' . Str::slug($artwork->title)
|
||||
. '_' . $artwork->id . '.jpg';
|
||||
if (Storage::disk('static')->exists('artworks/' . $basename)) {
|
||||
$artworkModel = Artwork::where('filename', $basename)->first();
|
||||
if (!$artworkModel) {
|
||||
$missingModel++;
|
||||
$this->command->error($basename . ' exists.');
|
||||
StashAndOptimizeLegacyArtworkJob::dispatch($legacyUser, $artwork);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
$this->command->line('Locally stored all of ' . $legacyUser->name . '\'s artworks.');
|
||||
}
|
||||
}
|
||||
}
|
||||
$current_page++;
|
||||
$response = $this->getResponseFromApi($current_page);
|
||||
}
|
||||
$this->command->info('Total Artworks: ' . $totalArtworks);
|
||||
$this->command->info('Total Missing: ' . $missingArtworks);
|
||||
$this->command->info('Total Missing Model: ' . $missingModel);
|
||||
}
|
||||
|
||||
private function getResponseFromApi($current_page) {
|
||||
$response = Http::timeout(180)
|
||||
->get('https://noagendaartgenerator.com/artistapi',
|
||||
[
|
||||
'p' => '7476',
|
||||
'page' => $current_page,
|
||||
]
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function populateLegacyArtworks() {
|
||||
$artworks = Artwork::whereNull('legacy_id')->get();
|
||||
foreach ($artworks as $artwork) {
|
||||
$file = pathinfo($artwork->filename);
|
||||
$filename = explode('_', $file['filename']);
|
||||
$legacy_id = end($filename);
|
||||
$artwork->legacy_id = $legacy_id;
|
||||
$artwork->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
1779
site/package-lock.json
generated
1779
site/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,20 @@
|
||||
"axios": "^1.1.2",
|
||||
"laravel-vite-plugin": "^0.7.5",
|
||||
"postcss": "^8.4.6",
|
||||
"sass": "^1.63.6",
|
||||
"tailwindcss": "^3.1.0",
|
||||
"vite": "^4.0.0"
|
||||
"vite": "^4.0.0",
|
||||
"wolfy87-eventemitter": "4.2.0"
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"aos": "^3.0.0-beta.6",
|
||||
"guillotine": "^1.3.1",
|
||||
"isotope-layout": "^3.0.6",
|
||||
"jquery": "^3.7.0",
|
||||
"jquery-nice-select": "^1.1.0",
|
||||
"js.cookie": "^0.0.4",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"waypoints": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
990
site/public/adm/adminer.css
Normal file
990
site/public/adm/adminer.css
Normal file
@@ -0,0 +1,990 @@
|
||||
/** theme "easy on the eyes" for Adminer by p.galkaev@miraidenshi-tech.jp */
|
||||
|
||||
@import url(//fonts.googleapis.com/css?family=Source+Sans+Pro:400,900);
|
||||
|
||||
/* reset
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
*,
|
||||
*:after,
|
||||
*:before {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
cursor: default;
|
||||
-webkit-appearance: none;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
|
||||
/* for font awesome */
|
||||
*:not(.fa) {
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
}
|
||||
|
||||
#logins a, #tables a, #tables span {
|
||||
background: none;
|
||||
}
|
||||
|
||||
p,
|
||||
form
|
||||
{
|
||||
margin: 0;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p:last-child,
|
||||
form:last-child
|
||||
{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.type,
|
||||
.options select
|
||||
{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
sup{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* js tooltip
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
.js .column {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
top: 50px;
|
||||
z-index: 9;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.js .column:not(.hidden){
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.js .column a{
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
flex-grow: 1;
|
||||
background: #fb4;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.js .column a:hover{
|
||||
background-color: gold;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#help {
|
||||
position: absolute;
|
||||
border: none;
|
||||
background: #fb4;
|
||||
font-family: monospace;
|
||||
z-index: 1;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#help a{
|
||||
color: black;
|
||||
height: 100%;
|
||||
display: block;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#help a:hover{
|
||||
background-color: gold;
|
||||
}
|
||||
|
||||
#help, .js .column{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* error and message
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
.error, .message {
|
||||
padding: 5px 15px 7px;
|
||||
margin: 10px 0;
|
||||
font-size: 14px;
|
||||
display: table;
|
||||
border-radius: 3px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.error{
|
||||
background-color: crimson;
|
||||
}
|
||||
|
||||
.message{
|
||||
background-color: seagreen;
|
||||
}
|
||||
|
||||
/* scroll bar
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
::selection {
|
||||
background-color: #2a65ae;
|
||||
}
|
||||
/*
|
||||
::-moz-selection {
|
||||
background-color: #333;
|
||||
}*/
|
||||
|
||||
/* scroll bar
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
::-webkit-scrollbar {
|
||||
background-color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #555;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar:vertical{
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:vertical{
|
||||
border-left: 0px solid black;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar:horizontal{
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:horizontal{
|
||||
border-top: 0px solid black;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner{
|
||||
color: black;
|
||||
background-color: black;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
::-webkit-resizer{
|
||||
background-color: #555;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
/* html and body
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
body{
|
||||
min-height: 100%;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
color: #ccc;
|
||||
background-color: black;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* headings
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
h1{
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
padding: 0 18px;
|
||||
border-bottom: 1px solid #444;
|
||||
font-weight: bold;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
color: #555;
|
||||
background: none;
|
||||
}
|
||||
|
||||
h2{
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-left: 50px;
|
||||
border-bottom: 1px solid #333;
|
||||
color: #2CC990;
|
||||
font-weight: bold;
|
||||
background: none;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h3{
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
margin: 40px 0 10px;
|
||||
color: #2CC990;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
/* links
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
a{
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover, a:visited{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:link:hover, a:visited:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* table
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
table{
|
||||
margin: 0;
|
||||
margin-bottom: 20px;
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
/*table-layout: fixed;*/
|
||||
}
|
||||
|
||||
tr:hover th,
|
||||
.checked th
|
||||
{
|
||||
background: #333 !important;
|
||||
color: #ddd;
|
||||
border-color: none;
|
||||
}
|
||||
|
||||
tr:hover td,
|
||||
.checked td
|
||||
{
|
||||
background: #222 !important;
|
||||
color: #ddd;
|
||||
border-color: none;
|
||||
}
|
||||
|
||||
.links + table tr:hover th{
|
||||
color: #ddd;
|
||||
background: #336f5a !important;
|
||||
}
|
||||
|
||||
.links + table tr:hover td{
|
||||
background: #2CC990 !important;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p + table{
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
tr{
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 0;
|
||||
border-right: 1px solid #333;
|
||||
padding: 0 12px;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
td:last-child,
|
||||
th:last-child{
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
th{
|
||||
position: relative;
|
||||
background: #222;
|
||||
font-weight: normal;
|
||||
width: 17%;
|
||||
border-left: 5px solid #336f5a;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .13);
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.checkable td:first-child{
|
||||
background: #222;
|
||||
border-right-style: solid;
|
||||
}
|
||||
|
||||
table.checkable th{
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
td{
|
||||
background: #000;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
.odd th{
|
||||
background: #222;
|
||||
}
|
||||
|
||||
.odd td{
|
||||
background: #000;
|
||||
}
|
||||
|
||||
thead td,
|
||||
thead th
|
||||
{
|
||||
background: transparent !important;
|
||||
color: #ccc;
|
||||
border-right-style: dashed;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table#edit-fields td,
|
||||
table#edit-fields th
|
||||
{
|
||||
padding: 0;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
table#edit-fields thead th,
|
||||
table#edit-fields thead td
|
||||
{
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
thead tr:hover th,
|
||||
thead tr:hover td,
|
||||
.links + table thead tr:hover th,
|
||||
.links + table thead tr:hover td,
|
||||
table#edit-fields thead tr:hover th,
|
||||
table#edit-fields thead tr:hover td
|
||||
{
|
||||
background-color: transparent !important;
|
||||
color: inherit !important;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .1) !important;
|
||||
}
|
||||
|
||||
thead tr:hover th{
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .13) !important;
|
||||
}
|
||||
|
||||
thead th {
|
||||
border-left-color: transparent;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* form
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea
|
||||
{
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
line-height: 28px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
padding-left: 10px;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input:hover,
|
||||
select:hover,
|
||||
input:focus,
|
||||
select:focus
|
||||
{
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
th input,
|
||||
td input,
|
||||
th select,
|
||||
td select,
|
||||
td textarea
|
||||
{
|
||||
background-color: transparent;
|
||||
color: pink;
|
||||
width: 100%;
|
||||
display: inline;
|
||||
border-left: 1px dashed #555;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
th input:hover,
|
||||
th select:hover,
|
||||
td input:hover,
|
||||
td select:hover,
|
||||
th input:focus,
|
||||
th select:focus,
|
||||
td input:focus,
|
||||
td select:focus
|
||||
{
|
||||
background-color: rgba(255, 255, 255, .15);
|
||||
}
|
||||
|
||||
th input[type='checkbox'],
|
||||
th input[type='radio'],
|
||||
td input[type='checkbox'],
|
||||
td input[type='radio']{
|
||||
border-left: none;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
td input + a,
|
||||
td input + a:visited
|
||||
{
|
||||
text-transform: uppercase;
|
||||
margin-left: 5px;
|
||||
color: dodgerblue;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
td input + a:hover{
|
||||
color: lightskyblue !important;
|
||||
}
|
||||
|
||||
input.icon{
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
input.icon::after{
|
||||
content: '';
|
||||
}
|
||||
|
||||
th select,
|
||||
td select
|
||||
{
|
||||
color: lightcoral;
|
||||
}
|
||||
|
||||
input[type='number'] {
|
||||
min-width: 55px;
|
||||
}
|
||||
|
||||
/* radio */
|
||||
input[type='radio']{
|
||||
-webkit-appearance: radio;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* checkbox */
|
||||
input[type='checkbox']{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 6px;
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
input[type=checkbox]:hover{
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
input[type=checkbox]::after {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
content: '×';
|
||||
left: 17%;
|
||||
top: 4.5%;
|
||||
color: #ccc;
|
||||
font-size: 35px;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type=checkbox]:hover::after {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
input[type=checkbox]:checked::after {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
td input[type='checkbox'],
|
||||
th input[type='checkbox']
|
||||
{
|
||||
margin-left: 10px;
|
||||
margin-right: 26px;
|
||||
}
|
||||
|
||||
td input[type='checkbox']::after{
|
||||
left: 10%;
|
||||
top: -2px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
td input[type='checkbox']:hover::after{
|
||||
color: #555;
|
||||
}
|
||||
|
||||
td input[type='checkbox']:checked::after{
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
p input:first-child{
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
label{
|
||||
line-height: 27px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
th label{
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
label input {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* submit */
|
||||
input[type='submit']{
|
||||
color: white;
|
||||
background-color: royalblue;
|
||||
padding: 0 25px;
|
||||
margin-right: 20px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
input[type='submit']:hover{
|
||||
background-color: #214ac5;
|
||||
}
|
||||
|
||||
/* select */
|
||||
select{
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
/* textarea */
|
||||
textarea{
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* fieldset */
|
||||
fieldset {
|
||||
display: inline;
|
||||
vertical-align: top;
|
||||
padding: 4px 7px 7px;
|
||||
margin: 0 5px 10px;
|
||||
border: 1px dashed #555;
|
||||
border-radius: 2px;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
fieldset > div{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
fieldset > div * + p{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
fieldset > div > div{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
fieldset > div > div:first-child{
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
fieldset > div input,
|
||||
fieldset > div select
|
||||
{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
fieldset > div input[type='checkbox']{
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
fieldset input{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
fieldset input[type='submit']{
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
fieldset input[type='submit']:last-of-type{
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
legend{
|
||||
font-size: 14px;
|
||||
background-color: #000;
|
||||
padding: 0 3px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* menu
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#menu{
|
||||
height: 100%;
|
||||
width: 300px;
|
||||
background-color: #333;
|
||||
position: relative;
|
||||
order: 1;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
overflow-y: overlay;
|
||||
}
|
||||
|
||||
#menu p {
|
||||
padding: 18px;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
/* logo */
|
||||
#h1{
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
.version {
|
||||
color: #555;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
/* db select */
|
||||
#dbs select{
|
||||
width: 228px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* links */
|
||||
#menu .links{
|
||||
padding-top: 0;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#menu .links a:nth-child(even){
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
#menu .links a{
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 127px;
|
||||
height: 31px;
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #555;
|
||||
line-height: 27px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#menu .links a.active,
|
||||
#menu .links a:hover
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
font-weight: normal;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* tables */
|
||||
#logins, #tables{
|
||||
border-bottom: none;
|
||||
line-height: 20px;
|
||||
padding: 18px 0;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
#tables br{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tables a {
|
||||
float: right;
|
||||
padding: 5px 18px 9px;
|
||||
line-height: 17px;
|
||||
color: #2CC990;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#tables .structure, #tables .view {
|
||||
float: none;
|
||||
display: block;
|
||||
color: inherit;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#logins a {
|
||||
display: block;
|
||||
padding: 5px 18px 9px;
|
||||
color: inherit;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#tables a.select.active,
|
||||
#tables a.select:hover
|
||||
{
|
||||
color: #fba;
|
||||
}
|
||||
|
||||
#logins a:hover,
|
||||
#tables a[title]:hover,
|
||||
#tables a.active,
|
||||
#tables a.select:hover + a,
|
||||
#tables a.select.active + a
|
||||
{
|
||||
background-color: #555;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* content
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#content{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
padding-bottom: 30px;
|
||||
overflow-y: auto !important;
|
||||
order: 2;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#breadcrumb{
|
||||
position: relative;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content h2{
|
||||
margin-left: -50px;
|
||||
}
|
||||
|
||||
/* links */
|
||||
#content .links a,
|
||||
code.jush-sql ~ a,
|
||||
#fieldset-history > a:first-child
|
||||
{
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#content .links a:hover,
|
||||
code.jush-sql ~ a:hover,
|
||||
#fieldset-history > a:first-child:hover
|
||||
{
|
||||
color: #eee;
|
||||
border-color: #eee;
|
||||
}
|
||||
|
||||
#ajaxstatus + *{
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
#ajaxstatus + *.links {
|
||||
margin-top: 0 !important;
|
||||
height: 65px;
|
||||
line-height: 55px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#ajaxstatus + .links a{
|
||||
white-space: nowrap;
|
||||
margin-right: 20px;
|
||||
padding: 0;
|
||||
padding-bottom: 5px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#ajaxstatus + .links a.active,
|
||||
#ajaxstatus + .links a:hover
|
||||
{
|
||||
border-bottom: 1px solid;
|
||||
border-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* fieldset search */
|
||||
#fieldset-search > div > *{
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* fieldset search */
|
||||
#fieldset-partition p{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* feldset history */
|
||||
#fieldset-history{
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#fieldset-history i{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fieldset-history input[type='submit']{
|
||||
flex-grow: 0;
|
||||
order: 1;
|
||||
margin-top: 1px;
|
||||
margin-left: 17px;
|
||||
}
|
||||
|
||||
#fieldset-history > div a:last-child{
|
||||
order: 2;
|
||||
}
|
||||
|
||||
#fieldset-history > a{
|
||||
flex-grow: 0;
|
||||
flex-basis: 5%;
|
||||
min-width: 45px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#fieldset-history > .time{
|
||||
flex-grow: 0;
|
||||
flex-basis: 5%;
|
||||
text-align: center;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
#fieldset-history > code{
|
||||
flex-grow: 1;
|
||||
flex-basis: 89%;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
#fieldset-history > .time{
|
||||
flex-grow: 0;
|
||||
flex-basis: 5%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* sql
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
.sqlarea{
|
||||
border: 1px solid #444 !important;
|
||||
width: 100% !important;
|
||||
padding: 12px 15px !important;
|
||||
font-size: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.jush-sql_code{
|
||||
color: #fafafa !important;
|
||||
font-family: 'Source Sans Pro', sans-serif !important;
|
||||
}
|
||||
|
||||
.jush a, .jush a:visited{
|
||||
color: #fba;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.jush a:hover{
|
||||
color: #fba;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.jush-php_quo, .jush-quo, .jush-quo_one, .jush-php_eot, .jush-apo, .jush-sql_apo, .jush-sqlite_apo, .jush-sql_quo, .jush-sql_eot{
|
||||
color: aquamarine;
|
||||
}
|
||||
|
||||
.jush-bac, .jush-php_bac, .jush-bra, .jush-mssql_bra, .jush-sqlite_quo{
|
||||
color: plum;
|
||||
}
|
||||
|
||||
.jush-num, .jush-clr{
|
||||
color: #85E2FF;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #000;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
code.jush-sql ~ a{
|
||||
position: relative;
|
||||
margin-left: 5px;
|
||||
/*margin-top: 20px;
|
||||
margin-bottom: 20px; */
|
||||
}
|
||||
|
||||
code.jush-sql ~ a:first-of-type{
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
code.jush-sql ~ a:first-of-type::before{
|
||||
content: '◀';
|
||||
color: #555;
|
||||
position: absolute;
|
||||
left: -22px;
|
||||
font-size: 22px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
/* logout form
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
body > form{
|
||||
position: absolute;
|
||||
}
|
||||
1795
site/public/adm/index.php
Normal file
1795
site/public/adm/index.php
Normal file
File diff suppressed because one or more lines are too long
1
site/public/css/filament/filament/app.css
Normal file
1
site/public/css/filament/filament/app.css
Normal file
File diff suppressed because one or more lines are too long
49
site/public/css/filament/forms/forms.css
Normal file
49
site/public/css/filament/forms/forms.css
Normal file
File diff suppressed because one or more lines are too long
1
site/public/css/filament/support/support.css
Normal file
1
site/public/css/filament/support/support.css
Normal file
@@ -0,0 +1 @@
|
||||
.fi-pagination-items,.fi-pagination-overview,.fi-pagination-records-per-page-select:not(.fi-compact){display:none}@supports (container-type:inline-size){.fi-pagination{container-type:inline-size}@container (min-width: 28rem){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@container (min-width: 56rem){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}@supports not (container-type:inline-size){@media (min-width:640px){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@media (min-width:768px){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{background-color:#333;border-radius:4px;color:#fff;font-size:14px;line-height:1.4;outline:0;position:relative;transition-property:transform,visibility,opacity;white-space:normal}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{border-top-color:initial;border-width:8px 8px 0;bottom:-7px;left:0;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:initial;border-width:0 8px 8px;left:0;top:-7px;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-left-color:initial;border-width:8px 0 8px 8px;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{border-right-color:initial;border-width:8px 8px 8px 0;left:-7px;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{color:#333;height:16px;width:16px}.tippy-arrow:before{border-color:transparent;border-style:solid;content:"";position:absolute}.tippy-content{padding:5px 9px;position:relative;z-index:1}.tippy-box[data-theme~=light]{background-color:#fff;box-shadow:0 0 20px 4px #9aa1b126,0 4px 80px -8px #24282f40,0 4px 4px -2px #5b5e6926;color:#26323d}.tippy-box[data-theme~=light][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff}.tippy-box[data-theme~=light][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff}.tippy-box[data-theme~=light]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light]>.tippy-svg-arrow{fill:#fff}.fi-sortable-ghost{opacity:.3}
|
||||
1
site/public/js/filament/filament/app.js
Normal file
1
site/public/js/filament/filament/app.js
Normal file
File diff suppressed because one or more lines are too long
13
site/public/js/filament/filament/echo.js
Normal file
13
site/public/js/filament/filament/echo.js
Normal file
File diff suppressed because one or more lines are too long
1
site/public/js/filament/forms/components/color-picker.js
Normal file
1
site/public/js/filament/forms/components/color-picker.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
123
site/public/js/filament/forms/components/file-upload.js
Normal file
123
site/public/js/filament/forms/components/file-upload.js
Normal file
File diff suppressed because one or more lines are too long
1
site/public/js/filament/forms/components/key-value.js
Normal file
1
site/public/js/filament/forms/components/key-value.js
Normal file
@@ -0,0 +1 @@
|
||||
function r({state:i}){return{state:i,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=o=>o===null?0:Array.isArray(o)?o.length:typeof o!="object"?0:Object.keys(o).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows),s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.rows=e,this.updateState()},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default};
|
||||
51
site/public/js/filament/forms/components/markdown-editor.js
Normal file
51
site/public/js/filament/forms/components/markdown-editor.js
Normal file
File diff suppressed because one or more lines are too long
143
site/public/js/filament/forms/components/rich-editor.js
Normal file
143
site/public/js/filament/forms/components/rich-editor.js
Normal file
File diff suppressed because one or more lines are too long
6
site/public/js/filament/forms/components/select.js
Normal file
6
site/public/js/filament/forms/components/select.js
Normal file
File diff suppressed because one or more lines are too long
1
site/public/js/filament/forms/components/tags-input.js
Normal file
1
site/public/js/filament/forms/components/tags-input.js
Normal file
@@ -0,0 +1 @@
|
||||
function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{["x-on:blur"]:"createTag()",["x-model"]:"newTag",["x-on:keydown"](t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},["x-on:paste"](){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default};
|
||||
1
site/public/js/filament/forms/components/textarea.js
Normal file
1
site/public/js/filament/forms/components/textarea.js
Normal file
@@ -0,0 +1 @@
|
||||
function t({initialHeight:e}){return{init:function(){this.render()},render:function(){this.$el.scrollHeight>0&&(this.$el.style.height=e+"rem",this.$el.style.height=this.$el.scrollHeight+"px")}}}export{t as default};
|
||||
1
site/public/js/filament/notifications/notifications.js
Normal file
1
site/public/js/filament/notifications/notifications.js
Normal file
File diff suppressed because one or more lines are too long
1
site/public/js/filament/support/async-alpine.js
Normal file
1
site/public/js/filament/support/async-alpine.js
Normal file
File diff suppressed because one or more lines are too long
35
site/public/js/filament/support/support.js
Normal file
35
site/public/js/filament/support/support.js
Normal file
File diff suppressed because one or more lines are too long
1
site/public/js/filament/tables/components/table.js
Normal file
1
site/public/js/filament/tables/components/table.js
Normal file
@@ -0,0 +1 @@
|
||||
function c(){return{collapsedGroups:[],isLoading:!1,selectedRecords:[],shouldCheckUniqueSelection:!0,init:function(){this.$wire.$on("deselectAllTableRecords",()=>this.deselectAllRecords()),this.$watch("selectedRecords",()=>{if(!this.shouldCheckUniqueSelection){this.shouldCheckUniqueSelection=!0;return}this.selectedRecords=[...new Set(this.selectedRecords)],this.shouldCheckUniqueSelection=!1})},mountBulkAction:function(e){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableBulkAction(e)},toggleSelectRecordsOnPage:function(){let e=this.getRecordsOnPage();if(this.areRecordsSelected(e)){this.deselectRecords(e);return}this.selectRecords(e)},toggleSelectRecordsInGroup:async function(e){if(this.isLoading=!0,this.areRecordsSelected(this.getRecordsInGroupOnPage(e))){this.deselectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e));return}this.selectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e)),this.isLoading=!1},getRecordsInGroupOnPage:function(e){let s=[];for(let t of this.$root.getElementsByClassName("fi-ta-record-checkbox"))t.dataset.group===e&&s.push(t.value);return s},getRecordsOnPage:function(){let e=[];for(let s of this.$root.getElementsByClassName("fi-ta-record-checkbox"))e.push(s.value);return e},selectRecords:function(e){for(let s of e)this.isRecordSelected(s)||this.selectedRecords.push(s)},deselectRecords:function(e){for(let s of e){let t=this.selectedRecords.indexOf(s);t!==-1&&this.selectedRecords.splice(t,1)}},selectAllRecords:async function(){this.isLoading=!0,this.selectedRecords=await this.$wire.getAllSelectableTableRecordKeys(),this.isLoading=!1},deselectAllRecords:function(){this.selectedRecords=[]},isRecordSelected:function(e){return this.selectedRecords.includes(e)},areRecordsSelected:function(e){return e.every(s=>this.isRecordSelected(s))},toggleCollapseGroup:function(e){if(this.isGroupCollapsed(e)){this.collapsedGroups.splice(this.collapsedGroups.indexOf(e),1);return}this.collapsedGroups.push(e)},isGroupCollapsed:function(e){return this.collapsedGroups.includes(e)},resetCollapsedGroups:function(){this.collapsedGroups=[]}}}export{c as default};
|
||||
37
site/public/js/filament/widgets/components/chart.js
Normal file
37
site/public/js/filament/widgets/components/chart.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow: /
|
||||
|
||||
7038
site/resources/css/style.css
Normal file
7038
site/resources/css/style.css
Normal file
File diff suppressed because it is too large
Load Diff
1
site/resources/css/style.css.map
Normal file
1
site/resources/css/style.css.map
Normal file
File diff suppressed because one or more lines are too long
1
site/resources/css/vendor/aos.css
vendored
Normal file
1
site/resources/css/vendor/aos.css
vendored
Normal file
File diff suppressed because one or more lines are too long
9828
site/resources/css/vendor/bootstrap.min.css
vendored
Normal file
9828
site/resources/css/vendor/bootstrap.min.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
site/resources/css/vendor/jquery.fancybox.min.css
vendored
Normal file
1
site/resources/css/vendor/jquery.fancybox.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
site/resources/css/vendor/nice-select.css
vendored
Normal file
1
site/resources/css/vendor/nice-select.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.nice-select{-webkit-tap-highlight-color:transparent;background-color:#fff;border-radius:5px;border:solid 1px #e8e8e8;-webkit-box-sizing:border-box;box-sizing:border-box;clear:both;cursor:pointer;display:block;float:left;font-family:inherit;font-size:14px;font-weight:normal;height:42px;line-height:40px;outline:0;padding-left:18px;padding-right:30px;position:relative;text-align:left !important;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;width:auto}.nice-select:hover{border-color:#dbdbdb}.nice-select:active,.nice-select.open,.nice-select:focus{border-color:#999}.nice-select:after{border-bottom:2px solid #999;border-right:2px solid #999;content:'';display:block;height:5px;margin-top:-4px;pointer-events:none;position:absolute;right:12px;top:50%;-webkit-transform-origin:66% 66%;-ms-transform-origin:66% 66%;transform-origin:66% 66%;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out;width:5px}.nice-select.open:after{-webkit-transform:rotate(-135deg);-ms-transform:rotate(-135deg);transform:rotate(-135deg)}.nice-select.open .list{opacity:1;pointer-events:auto;-webkit-transform:scale(1) translateY(0);-ms-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}.nice-select.disabled{border-color:#ededed;color:#999;pointer-events:none}.nice-select.disabled:after{border-color:#ccc}.nice-select.wide{width:100%}.nice-select.wide .list{left:0 !important;right:0 !important}.nice-select.right{float:right}.nice-select.right .list{left:auto;right:0}.nice-select.small{font-size:12px;height:36px;line-height:34px}.nice-select.small:after{height:4px;width:4px}.nice-select.small .option{line-height:34px;min-height:34px}.nice-select .list{background-color:#fff;border-radius:5px;-webkit-box-shadow:0 0 0 1px rgba(68,68,68,0.11);box-shadow:0 0 0 1px rgba(68,68,68,0.11);-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:4px;opacity:0;overflow:hidden;padding:0;pointer-events:none;position:absolute;top:100%;left:0;-webkit-transform-origin:50% 0;-ms-transform-origin:50% 0;transform-origin:50% 0;-webkit-transform:scale(0.75) translateY(-21px);-ms-transform:scale(0.75) translateY(-21px);transform:scale(0.75) translateY(-21px);-webkit-transition:all .2s cubic-bezier(0.5,0,0,1.25),opacity .15s ease-out;-o-transition:all .2s cubic-bezier(0.5,0,0,1.25),opacity .15s ease-out;transition:all .2s cubic-bezier(0.5,0,0,1.25),opacity .15s ease-out;z-index:9}.nice-select .list:hover .option:not(:hover){background-color:transparent !important}.nice-select .option{cursor:pointer;font-weight:400;line-height:40px;list-style:none;min-height:40px;outline:0;padding-left:18px;padding-right:29px;text-align:left;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}.nice-select .option:hover,.nice-select .option.focus,.nice-select .option.selected.focus{background-color:#f6f6f6}.nice-select .option.selected{font-weight:bold}.nice-select .option.disabled{background-color:transparent;color:#999;cursor:default}.no-csspointerevents .nice-select .list{display:none}.no-csspointerevents .nice-select.open .list{display:block}
|
||||
1
site/resources/css/vendor/slick-theme.css
vendored
Normal file
1
site/resources/css/vendor/slick-theme.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
@charset 'UTF-8';.slick-loading .slick-list{background:#fff url('../../img/ajax-loader.gif') center center no-repeat}@font-face{font-family:'slick';font-weight:normal;font-style:normal;src:url('../../fonts/slick.eot');src:url('../../fonts/slick.eot?#iefix') format('embedded-opentype'),url('../../fonts/slick.woff') format('woff'),url('../../fonts/slick.ttf') format('truetype'),url('../../fonts/slick.svg#slick') format('svg')}.slick-prev,.slick-next{font-size:0;line-height:0;position:absolute;top:50%;display:block;width:20px;height:20px;padding:0;-webkit-transform:translate(0,-50%);-ms-transform:translate(0,-50%);transform:translate(0,-50%);cursor:pointer;color:transparent;border:0;outline:0;background:transparent}.slick-prev:hover,.slick-prev:focus,.slick-next:hover,.slick-next:focus{color:transparent;outline:0;background:transparent}.slick-prev:hover:before,.slick-prev:focus:before,.slick-next:hover:before,.slick-next:focus:before{opacity:1}.slick-prev.slick-disabled:before,.slick-next.slick-disabled:before{opacity:.25}.slick-prev:before,.slick-next:before{font-family:'slick';font-size:20px;line-height:1;opacity:.75;color:white;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.slick-prev{left:-25px}[dir='rtl'] .slick-prev{right:-25px;left:auto}.slick-prev:before{content:'←'}[dir='rtl'] .slick-prev:before{content:'→'}.slick-next{right:-25px}[dir='rtl'] .slick-next{right:auto;left:-25px}.slick-next:before{content:'→'}[dir='rtl'] .slick-next:before{content:'←'}.slick-dotted.slick-slider{margin-bottom:30px}.slick-dots{position:absolute;bottom:-25px;display:block;width:100%;padding:0;margin:0;list-style:none;text-align:center}.slick-dots li{position:relative;display:inline-block;width:20px;height:20px;margin:0 5px;padding:0;cursor:pointer}.slick-dots li button{font-size:0;line-height:0;display:block;width:20px;height:20px;padding:5px;cursor:pointer;color:transparent;border:0;outline:0;background:transparent}.slick-dots li button:hover,.slick-dots li button:focus{outline:0}.slick-dots li button:hover:before,.slick-dots li button:focus:before{opacity:1}.slick-dots li button:before{font-family:'slick';font-size:6px;line-height:20px;position:absolute;top:0;left:0;width:20px;height:20px;content:'•';text-align:center;opacity:.25;color:black;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.slick-dots li.slick-active button:before{opacity:.75;color:black}
|
||||
1
site/resources/css/vendor/slick.css
vendored
Normal file
1
site/resources/css/vendor/slick.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.slick-slider{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none;-khtml-user-select:none;-ms-touch-action:pan-y;touch-action:pan-y;-webkit-tap-highlight-color:transparent}.slick-list{position:relative;display:block;overflow:hidden;margin:0;padding:0}.slick-list:focus{outline:0}.slick-list.dragging{cursor:pointer;cursor:hand}.slick-slider .slick-track,.slick-slider .slick-list{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.slick-track{position:relative;top:0;left:0;display:block;margin-left:auto;margin-right:auto}.slick-track:before,.slick-track:after{display:table;content:''}.slick-track:after{clear:both}.slick-loading .slick-track{visibility:hidden}.slick-slide{display:none;float:left;height:100%;min-height:1px}[dir='rtl'] .slick-slide{float:right}.slick-slide img{display:block}.slick-slide.slick-loading img{display:none}.slick-slide.dragging img{pointer-events:none}.slick-initialized .slick-slide{display:block}.slick-loading .slick-slide{visibility:hidden}.slick-vertical .slick-slide{display:block;height:auto;border:1px solid transparent}.slick-arrow.slick-hidden{display:none}
|
||||
BIN
site/resources/fonts/BakbakOneRegular.woff
Normal file
BIN
site/resources/fonts/BakbakOneRegular.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-Bold.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-Bold.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-BoldItalic.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-BoldItalic.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-ExtraLight.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-ExtraLight.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-ExtraLightItalic.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-ExtraLightItalic.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-Italic.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-Italic.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-Light.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-Light.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-LightItalic.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-LightItalic.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-Medium.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-Medium.woff
Normal file
Binary file not shown.
BIN
site/resources/fonts/ChakraPetch-MediumItalic.woff
Normal file
BIN
site/resources/fonts/ChakraPetch-MediumItalic.woff
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user