mirror of
https://github.com/sp-tarkov/forge.git
synced 2025-02-12 12:10:41 -05:00
Homepage Progress
Worked on: - Mod component templating - Added dark mode styles for homepage - Added benchmarking to the wolt import command - Added MySQL natural sort function Short todo: - Add updated time to mod component - Implement naturalsort function into homepage queries and measure performance difference - Migrate top navigation from old-build
This commit is contained in:
parent
3a81afe488
commit
787f796ad7
30
.env.example
30
.env.example
@ -1,4 +1,4 @@
|
||||
APP_NAME=Laravel
|
||||
APP_NAME="The Forge"
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
@ -12,6 +12,7 @@ APP_FAKER_LOCALE=en_US
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
# Much higher in production.
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
@ -19,19 +20,22 @@ LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
# Only 'mysql' and 'pgsql' are supported due to a 'naturalsort' database function.
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
DB_WOLTLAB_CONNECTION=sqlite
|
||||
# DB_WOLTLAB_HOST=127.0.0.1
|
||||
# DB_WOLTLAB_PORT=3306
|
||||
# DB_WOLTLAB_DATABASE=laravel
|
||||
# DB_WOLTLAB_USERNAME=root
|
||||
# DB_WOLTLAB_PASSWORD=
|
||||
# This is only needed if you are running the app:import-woltlab-data command.
|
||||
# For normal development you should just seed the database with fake data.
|
||||
DB_WOLTLAB_CONNECTION=mysql
|
||||
DB_WOLTLAB_HOST=127.0.0.1
|
||||
DB_WOLTLAB_PORT=3306
|
||||
DB_WOLTLAB_DATABASE=laravel
|
||||
DB_WOLTLAB_USERNAME=root
|
||||
DB_WOLTLAB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
|
@ -9,6 +9,7 @@ use App\Models\SptVersion;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Benchmark;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -33,21 +34,60 @@ class ImportWoltlabData extends Command
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$this->importUsers();
|
||||
$this->newLine();
|
||||
|
||||
$this->importLicenses();
|
||||
$totalTime = Benchmark::value(function () {
|
||||
$loadDataTime = Benchmark::value(function () {
|
||||
$this->loadData();
|
||||
});
|
||||
$this->info('Execution time: '.round($loadDataTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
|
||||
$this->importSptVersions();
|
||||
$importUsersTime = Benchmark::value(function () {
|
||||
$this->importUsers();
|
||||
});
|
||||
$this->info('Execution time: '.round($importUsersTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
|
||||
$importLicensesTime = Benchmark::value(function () {
|
||||
$this->importLicenses();
|
||||
});
|
||||
$this->info('Execution time: '.round($importLicensesTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
|
||||
$importSptVersionsTime = Benchmark::value(function () {
|
||||
$this->importSptVersions();
|
||||
});
|
||||
$this->info('Execution time: '.round($importSptVersionsTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
|
||||
$importModsTime = Benchmark::value(function () {
|
||||
$this->importMods();
|
||||
});
|
||||
$this->info('Execution time: '.round($importModsTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
|
||||
$importModVersionsTime = Benchmark::value(function () {
|
||||
$this->importModVersions();
|
||||
});
|
||||
$this->info('Execution time: '.round($importModVersionsTime[1], 2).'ms');
|
||||
$this->newLine();
|
||||
});
|
||||
|
||||
$this->newLine();
|
||||
$this->info('Data imported successfully');
|
||||
$this->info('Total execution time: '.round($totalTime[1], 2).'ms');
|
||||
}
|
||||
|
||||
protected function loadData(): void
|
||||
{
|
||||
// We're just going to dump a few things in memory to escape the N+1 problem.
|
||||
$this->output->write('Loading data into memory... ');
|
||||
$this->fileOptionValues = $this->getFileOptionValues();
|
||||
$this->fileContent = $this->getFileContent();
|
||||
$this->importMods();
|
||||
|
||||
$this->fileVersionContent = $this->getFileVersionContent();
|
||||
$this->fileVersionLabels = $this->getFileVersionLabels();
|
||||
$this->importModVersions();
|
||||
|
||||
$this->info('Data imported successfully.');
|
||||
$this->fileVersionContent = $this->getFileVersionContent();
|
||||
$this->info('Done.');
|
||||
}
|
||||
|
||||
protected function importUsers(): void
|
||||
@ -84,7 +124,6 @@ class ImportWoltlabData extends Command
|
||||
}, 'userID');
|
||||
|
||||
$this->info('Total users processed: '.$totalInserted);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
protected function importLicenses(): void
|
||||
@ -112,7 +151,6 @@ class ImportWoltlabData extends Command
|
||||
}, 'licenseID');
|
||||
|
||||
$this->info('Total licenses processed: '.$totalInserted);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
protected function importSptVersions(): void
|
||||
@ -125,7 +163,7 @@ class ImportWoltlabData extends Command
|
||||
$insertData[] = [
|
||||
'hub_id' => $version->labelID,
|
||||
'version' => $version->label,
|
||||
'color_class' => $version->cssClassName,
|
||||
'color_class' => $this->translateColour($version->cssClassName),
|
||||
];
|
||||
}
|
||||
|
||||
@ -140,7 +178,17 @@ class ImportWoltlabData extends Command
|
||||
}, 'labelID');
|
||||
|
||||
$this->info('Total licenses processed: '.$totalInserted);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
protected function translateColour(string $colour = ''): string
|
||||
{
|
||||
return match ($colour) {
|
||||
'green' => 'green',
|
||||
'slightly-outdated' => 'lime',
|
||||
'yellow' => 'yellow',
|
||||
'red' => 'red',
|
||||
default => 'gray',
|
||||
};
|
||||
}
|
||||
|
||||
protected function importMods(): void
|
||||
@ -155,20 +203,20 @@ class ImportWoltlabData extends Command
|
||||
DB::connection('mysql_woltlab')->table('filebase1_file')->chunkById(100, function (Collection $mods) use (&$command, &$curl, &$totalInserted) {
|
||||
|
||||
foreach ($mods as $mod) {
|
||||
if ($mod->fileID == 1 || $mod->fileID == 116 || $mod->fileID == 480) {
|
||||
// These are special cases that we don't want to import. Installers, base files, and the patchers.
|
||||
continue;
|
||||
}
|
||||
|
||||
$modContent = $this->fileContent[$mod->fileID] ?? [];
|
||||
$modOptions = $this->fileOptionValues[$mod->fileID] ?? [];
|
||||
$versionLabel = $this->fileVersionLabels[$mod->fileID] ?? [];
|
||||
|
||||
if (empty($versionLabel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$insertData[] = [
|
||||
'hub_id' => $mod->fileID,
|
||||
'user_id' => User::whereHubId($mod->userID)->value('id'),
|
||||
'name' => $modContent ? $modContent->subject : '',
|
||||
'slug' => $modContent ? Str::slug($modContent->subject) : '',
|
||||
'teaser' => $modContent ? $modContent->teaser : '',
|
||||
'teaser' => $modContent ? (strlen($modContent->teaser) > 100 ? Str::take($modContent->teaser, 97).'...' : $modContent->teaser) : '',
|
||||
'description' => $modContent ? $modContent->message : '',
|
||||
'thumbnail' => $this->fetchModThumbnail($command, $curl, $mod->fileID, $mod->iconHash, $mod->iconExtension),
|
||||
'license_id' => License::whereHubId($mod->licenseID)->value('id'),
|
||||
@ -194,7 +242,6 @@ class ImportWoltlabData extends Command
|
||||
curl_close($curl);
|
||||
|
||||
$this->info('Total mods processed: '.$totalInserted);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
protected function getFileOptionValues(): array
|
||||
@ -331,7 +378,7 @@ class ImportWoltlabData extends Command
|
||||
$command = $this;
|
||||
$totalInserted = 0;
|
||||
|
||||
DB::connection('mysql_woltlab')->table('filebase1_file_version')->chunkById(100, function (Collection $versions) use (&$command, &$totalInserted) {
|
||||
DB::connection('mysql_woltlab')->table('filebase1_file_version')->chunkById(500, function (Collection $versions) use (&$command, &$totalInserted) {
|
||||
|
||||
foreach ($versions as $version) {
|
||||
$versionContent = $this->fileVersionContent[$version->versionID] ?? [];
|
||||
@ -369,7 +416,6 @@ class ImportWoltlabData extends Command
|
||||
}, 'versionID');
|
||||
|
||||
$this->info('Total mod versions processed: '.$totalInserted);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
protected function fetchVirusTotalLink(array $options): string
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
class ColorHelper
|
||||
{
|
||||
public static function tagColorClasses($color): string
|
||||
{
|
||||
return match ($color) {
|
||||
'red' => 'bg-red-50 text-red-700 ring-red-600/20',
|
||||
'green' => 'bg-green-50 text-green-700 ring-green-600/20',
|
||||
'yellow' => 'bg-yellow-50 text-yellow-700 ring-yellow-600/20',
|
||||
default => 'bg-gray-50 text-gray-700 ring-gray-600/20',
|
||||
};
|
||||
}
|
||||
}
|
@ -23,6 +23,14 @@ class Mod extends Model
|
||||
'source_code_link',
|
||||
];
|
||||
|
||||
protected function slug(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (string $value) => strtolower($value),
|
||||
set: fn (string $value) => Str::slug($value),
|
||||
);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
@ -38,21 +46,54 @@ class Mod extends Model
|
||||
return $this->hasMany(ModVersion::class);
|
||||
}
|
||||
|
||||
public function versionLastUpdated()
|
||||
public function scopeWithTotalDownloads($query)
|
||||
{
|
||||
return $this->hasOne(ModVersion::class)->lastUpdated();
|
||||
$query->addSelect(['total_downloads' => ModVersion::selectRaw('SUM(downloads) AS total_downloads')
|
||||
->whereColumn('mod_id', 'mods.id'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function versionLatestSptVersion()
|
||||
public function latestSptVersion(): BelongsTo
|
||||
{
|
||||
return $this->hasOne(ModVersion::class)->latestSptVersion();
|
||||
return $this->belongsTo(ModVersion::class, 'latest_spt_version_id');
|
||||
}
|
||||
|
||||
protected function slug(): Attribute
|
||||
public function scopeWithLatestSptVersion($query)
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (string $value) => strtolower($value),
|
||||
set: fn (string $value) => Str::slug($value),
|
||||
);
|
||||
return $query
|
||||
->addSelect(['latest_spt_version_id' => ModVersion::select('id')
|
||||
->whereColumn('mod_id', 'mods.id')
|
||||
->orderByDesc(
|
||||
SptVersion::select('version')
|
||||
->whereColumn('mod_versions.spt_version_id', 'spt_versions.id')
|
||||
->orderByDesc('version')
|
||||
->take(1),
|
||||
)
|
||||
->orderByDesc('version')
|
||||
->take(1),
|
||||
])
|
||||
->with(['latestSptVersion', 'latestSptVersion.sptVersion']);
|
||||
}
|
||||
|
||||
public function lastUpdatedVersion(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ModVersion::class, 'last_updated_spt_version_id');
|
||||
}
|
||||
|
||||
public function scopeWithLastUpdatedVersion($query)
|
||||
{
|
||||
return $query
|
||||
->addSelect(['last_updated_spt_version_id' => ModVersion::select('id')
|
||||
->whereColumn('mod_id', 'mods.id')
|
||||
->orderByDesc('updated_at')
|
||||
->take(1),
|
||||
])
|
||||
->orderByDesc(
|
||||
ModVersion::select('updated_at')
|
||||
->whereColumn('mod_id', 'mods.id')
|
||||
->orderByDesc('updated_at')
|
||||
->take(1)
|
||||
)
|
||||
->with(['lastUpdatedVersion', 'lastUpdatedVersion.sptVersion']);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@ -26,20 +25,8 @@ class ModVersion extends Model
|
||||
return $this->belongsTo(Mod::class);
|
||||
}
|
||||
|
||||
public function sptVersion(): belongsTo
|
||||
public function sptVersion(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(SptVersion::class);
|
||||
}
|
||||
|
||||
public function scopeLastUpdated(Builder $query): void
|
||||
{
|
||||
$query->orderByDesc('created_at');
|
||||
}
|
||||
|
||||
public function scopeLatestSptVersion(Builder $query): void
|
||||
{
|
||||
$query->orderByDesc(
|
||||
SptVersion::select('spt_versions.version')->whereColumn('mod_versions.spt_version_id', 'spt_versions.id')
|
||||
)->orderByDesc('mod_versions.version');
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use App\Helpers\ColorHelper;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class ModList extends Component
|
||||
{
|
||||
public $mods;
|
||||
public Collection $mods;
|
||||
|
||||
public string $versionScope;
|
||||
|
||||
@ -16,11 +16,6 @@ class ModList extends Component
|
||||
{
|
||||
$this->mods = $mods;
|
||||
$this->versionScope = $versionScope;
|
||||
|
||||
foreach ($this->mods as $mod) {
|
||||
$color = $mod->{$this->versionScope}->sptVersion->color_class;
|
||||
$mod->colorClass = ColorHelper::tagColorClasses($color);
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -24,17 +24,36 @@ class ModListSection extends Component
|
||||
|
||||
private function fetchFeaturedMods(): Collection
|
||||
{
|
||||
return Mod::with('versionLatestSptVersion.sptVersion')->whereFeatured(true)->take(6)->get();
|
||||
return Mod::select(['id', 'user_id', 'name', 'slug', 'teaser', 'thumbnail', 'featured'])
|
||||
->withLatestSptVersion()
|
||||
->withTotalDownloads()
|
||||
->with('user:id,name')
|
||||
->where('featured', true)
|
||||
->latest()
|
||||
->limit(6)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function fetchLatestMods(): Collection
|
||||
{
|
||||
return Mod::with('versionLatestSptVersion.sptVersion')->latest()->take(6)->get();
|
||||
return Mod::select(['id', 'user_id', 'name', 'slug', 'teaser', 'thumbnail', 'featured'])
|
||||
->withLatestSptVersion()
|
||||
->withTotalDownloads()
|
||||
->with('user:id,name')
|
||||
->latest()
|
||||
->limit(6)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function fetchUpdatedMods(): Collection
|
||||
{
|
||||
return Mod::with('versionLastUpdated.sptVersion')->take(6)->get();
|
||||
return Mod::select(['id', 'user_id', 'name', 'slug', 'teaser', 'thumbnail', 'featured'])
|
||||
->withLastUpdatedVersion()
|
||||
->withTotalDownloads()
|
||||
->with('user:id,name')
|
||||
->latest()
|
||||
->limit(6)
|
||||
->get();
|
||||
}
|
||||
|
||||
public function getSections(): array
|
||||
@ -43,17 +62,17 @@ class ModListSection extends Component
|
||||
[
|
||||
'title' => 'Featured Mods',
|
||||
'mods' => $this->modsFeatured,
|
||||
'versionScope' => 'versionLatestSptVersion',
|
||||
'versionScope' => 'latestSptVersion',
|
||||
],
|
||||
[
|
||||
'title' => 'Latest Mods',
|
||||
'title' => 'Newest Mods',
|
||||
'mods' => $this->modsLatest,
|
||||
'versionScope' => 'versionLatestSptVersion',
|
||||
'versionScope' => 'latestSptVersion',
|
||||
],
|
||||
[
|
||||
'title' => 'Recently Updated Mods',
|
||||
'mods' => $this->modsUpdated,
|
||||
'versionScope' => 'versionLastUpdated',
|
||||
'versionScope' => 'lastUpdatedVersion',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class ModVersionTag extends Component
|
||||
{
|
||||
public string $tagColor;
|
||||
|
||||
public function __construct($tagColor)
|
||||
{
|
||||
$this->tagColor = $tagColor;
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('components.mod-version-tag');
|
||||
}
|
||||
|
||||
public function tagClasses($tagColor): string
|
||||
{
|
||||
return match ($this->tagColor) {
|
||||
'red' => 'bg-red-50 text-red-700 ring-red-600/20',
|
||||
'green' => 'bg-green-50 text-green-700 ring-green-600/20',
|
||||
'yellow' => 'bg-yellow-50 text-yellow-700 ring-yellow-600/20',
|
||||
default => 'bg-gray-50 text-gray-700 ring-gray-600/20',
|
||||
};
|
||||
}
|
||||
}
|
@ -33,10 +33,7 @@
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
},
|
||||
"files": [
|
||||
"app/Helpers/ColorHelper.php"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
@ -16,7 +16,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||
'default' => env('DB_CONNECTION', 'mysql'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -13,7 +13,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('hub_id')->nullable()->unique()->default(null);
|
||||
$table->bigInteger('hub_id')->nullable()->default(null)->unique();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
|
@ -10,7 +10,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('licenses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('hub_id')->nullable()->unique()->default(null);
|
||||
$table->bigInteger('hub_id')->nullable()->default(null)->unique();
|
||||
$table->string('name');
|
||||
$table->string('link');
|
||||
$table->softDeletes();
|
||||
|
@ -12,7 +12,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('mods', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('hub_id')->nullable()->unique()->default(null);
|
||||
$table->bigInteger('hub_id')->nullable()->default(null)->unique();
|
||||
$table->foreignIdFor(User::class)->constrained('users');
|
||||
$table->string('name');
|
||||
$table->string('slug');
|
||||
|
@ -10,7 +10,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('spt_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('hub_id')->nullable()->unique()->default(null);
|
||||
$table->bigInteger('hub_id')->nullable()->default(null)->unique();
|
||||
$table->string('version');
|
||||
$table->string('color_class');
|
||||
$table->softDeletes();
|
||||
|
@ -12,7 +12,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('mod_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('hub_id')->nullable()->unique()->default(null);
|
||||
$table->bigInteger('hub_id')->nullable()->default(null)->unique();
|
||||
$table->foreignIdFor(Mod::class)->constrained('mods');
|
||||
$table->string('version');
|
||||
$table->longText('description');
|
||||
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (config('database.default') === 'sqlite') {
|
||||
throw new \Exception('This project does not support SQLite. Update to MySQL or PostgreSQL.');
|
||||
}
|
||||
|
||||
if (config('database.default') === 'mysql') {
|
||||
// https://www.drupal.org/project/natsort
|
||||
DB::unprepared("
|
||||
DROP FUNCTION IF EXISTS naturalsort;
|
||||
CREATE FUNCTION naturalsort (s VARCHAR (255)) RETURNS VARCHAR (255) NO SQL DETERMINISTIC BEGIN
|
||||
DECLARE orig VARCHAR (255) DEFAULT s;
|
||||
DECLARE ret VARCHAR (255) DEFAULT '';
|
||||
IF s IS NULL THEN
|
||||
RETURN NULL;
|
||||
ELSEIF NOT s REGEXP '[0-9]' THEN
|
||||
SET ret = s;
|
||||
ELSE
|
||||
SET s = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(s, '0', '#'), '1', '#'), '2', '#'), '3', '#'), '4', '#');
|
||||
SET s = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(s, '5', '#'), '6', '#'), '7', '#'), '8', '#'), '9', '#');
|
||||
SET s = REPLACE(s, '.#', '##');
|
||||
SET s = REPLACE(s, '#,#', '###');
|
||||
BEGIN
|
||||
DECLARE numpos INT;
|
||||
DECLARE numlen INT;
|
||||
DECLARE numstr VARCHAR (255);
|
||||
lp1: LOOP
|
||||
SET numpos = locate('#', s);
|
||||
IF numpos = 0 THEN
|
||||
SET ret = concat(ret, s);
|
||||
LEAVE lp1;
|
||||
END IF;
|
||||
SET ret = concat(ret, substring(s, 1, numpos - 1));
|
||||
SET s = substring(s, numpos);
|
||||
SET orig = substring(orig, numpos);
|
||||
SET numlen = char_length(s) - char_length(trim(LEADING '#' FROM s));
|
||||
SET numstr = cast(REPLACE(substring(orig, 1, numlen), ',', '') AS DECIMAL (13, 3));
|
||||
SET numstr = lpad(numstr, 15, '0');
|
||||
SET ret = concat(ret, '[', numstr, ']');
|
||||
SET s = substring(s, numlen + 1);
|
||||
SET orig = substring(orig, numlen + 1);
|
||||
END LOOP;
|
||||
END;
|
||||
END IF;
|
||||
SET ret = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ret, ' ', ''), ',', ''), ':', ''), '.', ''), ';', '' ), '(', ''), ')', '');
|
||||
RETURN ret;
|
||||
END;
|
||||
");
|
||||
}
|
||||
|
||||
if (config('database.default') === 'pgsql') {
|
||||
// http://www.rhodiumtoad.org.uk/junk/naturalsort.sql
|
||||
DB::unprepared('
|
||||
create or replace function naturalsort(text)
|
||||
returns bytea language sql immutable strict as
|
||||
$f$ select string_agg(convert_to(coalesce(r[2],length(length(r[1])::text) || length(r[1])::text || r[1]),\'SQL_ASCII\'),\'\x00\')
|
||||
from regexp_matches($1, \'0*([0-9]+)|([^0-9]+)\', \'g\') r; $f$;
|
||||
');
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (config('database.default') === 'sqlite') {
|
||||
throw new \Exception('This project does not support SQLite. Update to MySQL or PostgreSQL.');
|
||||
}
|
||||
|
||||
if (config('database.default') === 'mysql' || config('database.default') === 'pgsql') {
|
||||
DB::unprepared('DROP FUNCTION IF EXISTS naturalsort');
|
||||
}
|
||||
}
|
||||
};
|
@ -8,9 +8,33 @@
|
||||
|
||||
button[type="submit"]:not([role="menuitem"]),
|
||||
button[type="button"]:not([role="menuitem"]) {
|
||||
@apply border border-transparent rounded-md text-white bg-gray-900 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-600
|
||||
@apply border border-transparent rounded-md py-2 px-4 text-white dark:text-gray-100 bg-gray-900 dark:bg-gray-700 hover:bg-gray-800 dark:hover:bg-black dark:hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-600 dark:focus:ring-gray-500 transition-all duration-200
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@apply text-gray-800 focus:ring-gray-600 border-gray-300 rounded
|
||||
@apply text-gray-800 dark:text-gray-300 focus:ring-gray-600 dark:focus:ring-gray-500 border-gray-300 dark:border-gray-700 rounded;
|
||||
}
|
||||
|
||||
.badge-version {
|
||||
@apply bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-100;
|
||||
|
||||
&.red {
|
||||
@apply bg-red-100 dark:bg-red-700 text-red-700 dark:text-red-100;
|
||||
}
|
||||
|
||||
&.green {
|
||||
@apply bg-green-100 dark:bg-green-700 text-green-700 dark:text-green-100;
|
||||
}
|
||||
|
||||
&.emerald {
|
||||
@apply bg-emerald-100 dark:bg-emerald-700 text-emerald-700 dark:text-emerald-100;
|
||||
}
|
||||
|
||||
&.lime {
|
||||
@apply bg-lime-100 dark:bg-lime-700 text-lime-700 dark:text-lime-100;
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
@apply bg-yellow-100 dark:bg-yellow-700 text-yellow-700 dark:text-yellow-100;
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,37 @@
|
||||
import './bootstrap';
|
||||
import "./bootstrap";
|
||||
|
||||
var themeToggleDarkIcon = document.getElementById("theme-toggle-dark-icon");
|
||||
var themeToggleLightIcon = document.getElementById("theme-toggle-light-icon");
|
||||
|
||||
if (
|
||||
localStorage.getItem("color-theme") === "dark" ||
|
||||
(!("color-theme" in localStorage) &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
themeToggleLightIcon.classList.remove("hidden");
|
||||
} else {
|
||||
themeToggleDarkIcon.classList.remove("hidden");
|
||||
}
|
||||
|
||||
var themeToggleBtn = document.getElementById("theme-toggle");
|
||||
themeToggleBtn.addEventListener("click", function () {
|
||||
themeToggleDarkIcon.classList.toggle("hidden");
|
||||
themeToggleLightIcon.classList.toggle("hidden");
|
||||
if (localStorage.getItem("color-theme")) {
|
||||
if (localStorage.getItem("color-theme") === "light") {
|
||||
document.documentElement.classList.add("dark");
|
||||
localStorage.setItem("color-theme", "dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
localStorage.setItem("color-theme", "light");
|
||||
}
|
||||
} else {
|
||||
if (document.documentElement.classList.contains("dark")) {
|
||||
document.documentElement.classList.remove("dark");
|
||||
localStorage.setItem("color-theme", "light");
|
||||
} else {
|
||||
document.documentElement.classList.add("dark");
|
||||
localStorage.setItem("color-theme", "dark");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 84 B |
@ -1 +1 @@
|
||||
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
|
||||
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
|
||||
|
49
resources/views/components/footer.blade.php
Normal file
49
resources/views/components/footer.blade.php
Normal file
@ -0,0 +1,49 @@
|
||||
<footer class="bg-gray-900" aria-labelledby="footer-heading">
|
||||
<h2 id="footer-heading" class="sr-only">Footer</h2>
|
||||
<div class="mx-auto max-w-7xl px-6 pb-8 pt-14 sm:pt-20 lg:px-8 lg:pt-29">
|
||||
<div class="xl:grid xl:grid-cols-3 xl:gap-8">
|
||||
<div>
|
||||
<p class="text-lg italic font-extrabold leading-6 text-white">The Forge</p>
|
||||
</div>
|
||||
<div class="mt-16 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8 xl:col-span-2 xl:mt-0">
|
||||
<div class="sm:order-first">
|
||||
<h3 class="text-sm font-semibold leading-6 text-white">Single Player Tarkov</h3>
|
||||
<ul role="list" class="mt-6 space-y-4">
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">About</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Articles</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Documentation</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Mods</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Support</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sm:order-last">
|
||||
<h3 class="text-sm font-semibold leading-6 text-white">Escape from Tarkov</h3>
|
||||
<ul role="list" class="mt-6 space-y-4">
|
||||
<li>
|
||||
<a href="https://www.escapefromtarkov.com/preorder-page" class="text-sm leading-6 text-gray-300 hover:text-white">Purchase</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://escapefromtarkov.fandom.com/wiki/Escape_from_Tarkov_Wiki" class="text-sm leading-6 text-gray-300 hover:text-white">Wiki</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold leading-6 text-white">Legal</h3>
|
||||
<ul role="list" class="mt-6 space-y-4">
|
||||
<li>
|
||||
<a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Community Guidelines</a>
|
||||
</li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Terms of Service</a>
|
||||
</li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Privacy Policy</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">Disclaimer</a></li>
|
||||
<li><a href="#" class="text-sm leading-6 text-gray-300 hover:text-white">DMCA</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 border-t border-white/10 pt-8 md:flex md:items-center md:justify-between">
|
||||
<p class="mt-8 text-xs leading-5 text-gray-400 md:order-1 md:mt-0">© {{ date('Y') }} {{ config('app.name', 'The Forge') }}. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
@ -1,40 +1,40 @@
|
||||
@props(['mods', 'versionScope'])
|
||||
|
||||
<ul role="list" {{ $attributes->class(['grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3']) }}>
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
@foreach ($mods as $mod)
|
||||
<li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white shadow">
|
||||
<div class="flex w-full items-center justify-between space-x-6 p-4">
|
||||
<img class="h-16 w-16 flex-shrink-0 rounded-[5px] bg-gray-300" src="https://placehold.co/300x300/EEE/31343C?font=open-sans&text=MOD" alt="">
|
||||
<div class="flex-1 truncate">
|
||||
<div class="flex items-center space-x-3">
|
||||
<h3 class="truncate text-sm font-medium text-gray-900">{{ $mod->name }}</h3>
|
||||
<span class="{{ $mod->colorClass }} inline-flex flex-shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium ring-1 ring-inset">
|
||||
{{ $mod->{$versionScope}->sptVersion->version }}
|
||||
</span>
|
||||
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}">
|
||||
<div class="flex flex-col group h-full w-full max-w-md mx-auto bg-white dark:bg-gray-950 rounded-xl shadow-md dark:shadow-gray-950 drop-shadow-2xl overflow-hidden md:max-w-2xl hover:shadow-lg hover:bg-gray-50 dark:hover:bg-black hover:shadow-gray-400 dark:hover:shadow-black transition-all duration-200">
|
||||
<div class="h-auto md:h-full md:flex">
|
||||
<div class="h-auto md:h-full md:shrink-0 overflow-hidden">
|
||||
@if(empty($mod->thumbnail))
|
||||
<img src="https://placehold.co/450x450/EEE/31343C?font=source-sans-pro&text={{ $mod->name }}" alt="{{ $mod->name }}" class="block dark:hidden h-48 w-full object-cover md:h-full md:w-48 transform group-hover:scale-110 transition-all duration-200">
|
||||
<img src="https://placehold.co/450x450/31343C/EEE?font=source-sans-pro&text={{ $mod->name }}" alt="{{ $mod->name }}" class="hidden dark:block h-48 w-full object-cover md:h-full md:w-48 transform group-hover:scale-110 transition-all duration-200">
|
||||
@else
|
||||
<img src="{{ $mod->thumbnail }}" alt="{{ $mod->name }}" class="h-48 w-full object-cover md:h-full md:w-48 transform group-hover:scale-110 transition-all duration-200">
|
||||
@endif
|
||||
</div>
|
||||
<p class="mt-1 truncate text-sm text-gray-500">{{ $mod->description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="-mt-px flex divide-x divide-gray-200">
|
||||
<div class="flex w-0 flex-1">
|
||||
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}" class="relative -mr-px inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-bl-lg border border-t-0 border-transparent py-4 text-sm font-semibold text-gray-900">
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/>
|
||||
</svg>
|
||||
{{ __('View Details') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="-ml-px flex w-0 flex-1">
|
||||
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}/download" class="relative inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-br-lg border border-t-0 border-transparent py-4 text-sm font-semibold text-gray-900">
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9.75v6.75m0 0-3-3m3 3 3-3m-8.25 6a4.5 4.5 0 0 1-1.41-8.775 5.25 5.25 0 0 1 10.233-2.33 3 3 0 0 1 3.758 3.848A3.752 3.752 0 0 1 18 19.5H6.75Z"/>
|
||||
</svg>
|
||||
{{ __('Download') }}
|
||||
</a>
|
||||
<div class="flex flex-col w-full justify-between p-5">
|
||||
<div>
|
||||
<div class="flex justify-between items-center space-x-3">
|
||||
<h3 class="block mt-1 text-lg leading-tight font-medium text-black dark:text-white group-hover:underline">{{ $mod->name }}</h3>
|
||||
<span class="badge-version {{ $mod->{$versionScope}->sptVersion->color_class }} inline-flex items-center rounded-md px-2 py-1 text-xs font-medium text-nowrap">
|
||||
{{ $mod->{$versionScope}->sptVersion->version }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="mt-2 text-slate-500 dark:text-gray-300">{{ $mod->teaser }}</p>
|
||||
</div>
|
||||
<p class="text-slate-700 dark:text-gray-300 text-sm">
|
||||
<span>By {{ $mod->user->name }}</span>
|
||||
@if (!is_null($mod->total_downloads))
|
||||
<span>– {{ Number::format($mod->total_downloads) }} downloads</span>
|
||||
@endif
|
||||
@if(!is_null($mod->updated_at))
|
||||
<span>– updated {{ $mod->updated_at }}</span>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</a>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -1,9 +1,9 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
|
||||
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
|
||||
$classes = ($active ?? false)
|
||||
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 dark:border-gray-800 text-sm font-medium leading-5 text-gray-900 dark:text-gray-300 focus:outline-none focus:border-indigo-700 dark:focus:border-gray-700 transition duration-150 ease-in-out'
|
||||
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent dark:border-gray-800 text-sm font-medium leading-5 text-gray-500 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-500 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-500 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<div {{ $attributes->class(['md:flex md:items-center md:justify-between border-b pb-4 mb-6']) }}>
|
||||
<div {{ $attributes->class(['md:flex md:items-center md:justify-between border-b dark:border-b-gray-800 pb-4 mb-6']) }}>
|
||||
<div class="min-w-0 flex-1">
|
||||
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">{{ __($title) }}</h2>
|
||||
<h2 class="text-2xl font-bold leading-7 text-gray-900 dark:text-gray-200 sm:truncate sm:text-3xl sm:tracking-tight">{{ __($title) }}</h2>
|
||||
</div>
|
||||
@if (isset($buttonText) && isset($buttonLink))
|
||||
<div class="mt-4 flex md:ml-4 md:mt-0">
|
||||
<a href="{{ $buttonLink }}">
|
||||
<button type="button" class="ml-3 inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">{{ __($buttonText) }}</button>
|
||||
<button type="button">{{ __($buttonText) }}</button>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
@ -1,9 +1,9 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
|
||||
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
|
||||
$classes = ($active ?? false)
|
||||
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 dark:bg-gray-800 focus:outline-none focus:text-indigo-800 dark:focus:text-gray-300 focus:bg-indigo-100 dark:focus:bg-gray-700 focus:border-indigo-700 dark:focus:border-gray-700 transition duration-150 ease-in-out'
|
||||
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-500 hover:bg-gray-50 dark:hover:bg-gray-800 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-800 dark:focus:text-gray-300 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="items-center justify-between gap-x-6 bg-gray-900 px-6 py-2.5 sm:pr-3.5 lg:pl-8">
|
||||
<p class="text-center text-sm leading-6 text-white">Notice: The Forge is currently under
|
||||
<div class="items-center justify-between gap-x-6 text-gray-200 bg-gray-900 dark:text-gray-900 dark:bg-gray-100 px-6 py-2.5 sm:pr-3.5 lg:pl-8">
|
||||
<p class="text-center text-sm leading-6">Notice: The Forge is currently under
|
||||
<em class="font-bold">heavy</em> construction. Expect nothing to work.</p>
|
||||
</div>
|
||||
|
@ -1,29 +1,26 @@
|
||||
<x-app-layout>
|
||||
|
||||
<div class="pt-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||
{{-- Welcome Section --}}
|
||||
<div class="relative isolate overflow-hidden bg-gray-900 px-6 py-24 sm:py-32 lg:px-8 rounded-md">
|
||||
<video autoplay muted loop class="absolute inset-0 -z-10 h-full w-full object-cover">
|
||||
<source src="/video/welcome.mp4" type="video/mp4">
|
||||
</video>
|
||||
<div class="hidden sm:absolute sm:-top-10 sm:right-1/2 sm:-z-10 sm:mr-10 sm:block sm:transform-gpu sm:blur-3xl" aria-hidden="true">
|
||||
<div class="aspect-[1097/845] w-[68.5625rem] bg-gradient-to-tr from-[#333] to-[#000] opacity-20" style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"></div>
|
||||
</div>
|
||||
<div class="absolute -top-52 left-1/2 -z-10 -translate-x-1/2 transform-gpu blur-3xl sm:top-[-28rem] sm:ml-16 sm:translate-x-0 sm:transform-gpu" aria-hidden="true">
|
||||
<div class="aspect-[1097/845] w-[68.5625rem] bg-gradient-to-tr from-[#333] to-[#000] opacity-20" style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"></div>
|
||||
</div>
|
||||
<div class="mx-auto max-w-2xl text-center">
|
||||
<h2 class="text-4xl font-bold tracking-tight text-white sm:text-6xl drop-shadow-md">Step into
|
||||
<em>{{ config('app.name', 'The Forge') }}</em></h2>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-300 drop-shadow-md">The greatest resource available for Single Player Tarkov modifications. Where modding legends are made. Discover powerful tools, expert-written guides, and exclusive mods. Craft your vision. Transform the game.</p>
|
||||
</div>
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-900 overflow-hidden shadow-xl dark:shadow-gray-900 sm:rounded-lg">
|
||||
<div class="relative isolate overflow-hidden bg-gray-900 dark:bg-gray-800 px-6 py-24 sm:py-32 lg:px-8 rounded-md">
|
||||
<video autoplay muted loop class="absolute inset-0 -z-10 h-full w-full object-cover">
|
||||
<source src="/video/welcome.mp4" type="video/mp4">
|
||||
</video>
|
||||
<div class="hidden sm:absolute sm:-top-10 sm:right-1/2 sm:-z-10 sm:mr-10 sm:block sm:transform-gpu sm:blur-3xl" aria-hidden="true">
|
||||
<div class="aspect-[1097/845] w-[68.5625rem] bg-gradient-to-tr from-[#333] to-[#000] opacity-20" style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"></div>
|
||||
</div>
|
||||
<div class="absolute -top-52 left-1/2 -z-10 -translate-x-1/2 transform-gpu blur-3xl sm:top-[-28rem] sm:ml-16 sm:translate-x-0 sm:transform-gpu" aria-hidden="true">
|
||||
<div class="aspect-[1097/845] w-[68.5625rem] bg-gradient-to-tr from-[#333] to-[#000] opacity-20" style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"></div>
|
||||
</div>
|
||||
<div class="mx-auto max-w-2xl text-center">
|
||||
<h2 class="text-4xl font-bold tracking-tight text-white sm:text-6xl drop-shadow-md">Step into
|
||||
<em class="dark:text-gray-400">{{ config('app.name', 'The Forge') }}</em></h2>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-300 drop-shadow-md">The greatest resource available for Single Player Tarkov modifications. Where modding legends are made. Discover powerful tools, expert-written guides, and exclusive mods. Craft your vision. Transform the game.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pb-10">
|
||||
<x-mod-list-section/>
|
||||
</div>
|
||||
<div class="pb-10">
|
||||
<x-mod-list-section/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,14 +7,19 @@
|
||||
|
||||
<title>{{ config('app.name', 'The Forge') }}</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.bunny.net" rel="preconnect">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet">
|
||||
|
||||
{{-- Handle setting the dark mode theme. Done here to avoid FOUC --}}
|
||||
<script>
|
||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
|
||||
<!-- Styles -->
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
@ -23,24 +28,24 @@
|
||||
|
||||
<x-banner/>
|
||||
|
||||
<div class="min-h-screen bg-gray-100">
|
||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-800">
|
||||
@livewire('navigation-menu')
|
||||
|
||||
<!-- Page Heading -->
|
||||
@if (isset($header))
|
||||
<header class="bg-white shadow">
|
||||
<header class="bg-white dark:bg-gray-800 shadow dark:shadow-white">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
{{ $header }}
|
||||
</div>
|
||||
</header>
|
||||
@endif
|
||||
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
<main class="py-12">
|
||||
{{ $slot }}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<x-footer/>
|
||||
|
||||
@stack('modals')
|
||||
|
||||
@livewireScripts
|
||||
|
@ -1,27 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||
<link href="https://fonts.bunny.net" rel="preconnect">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
{{-- Handle setting the dark mode theme. Done here to avoid FOUC --}}
|
||||
<script>
|
||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Styles -->
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body>
|
||||
<div class="font-sans text-gray-900 antialiased">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body>
|
||||
<div class="font-sans text-gray-900 antialiased">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
|
||||
@livewireScripts
|
||||
</body>
|
||||
@livewireScripts
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,54 +0,0 @@
|
||||
<div class="pb-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||
|
||||
<div class="border-b border-gray-200 bg-white px-4 py-5 sm:px-6">
|
||||
<div class="-ml-4 -mt-2 flex flex-wrap items-center justify-between sm:flex-nowrap">
|
||||
<div class="ml-4 mt-2">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900">{{ __('Latest Mods') }}</h3>
|
||||
</div>
|
||||
<div class="ml-4 mt-2 flex-shrink-0">
|
||||
<button type="button" class="relative inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">{{ __('View All') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul role="list" class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@foreach ($latestMods as $mod)
|
||||
<li class="col-span-1 divide-y divide-gray-200 rounded-lg bg-white shadow">
|
||||
<div class="flex w-full items-center justify-between space-x-6 p-6">
|
||||
<div class="flex-1 truncate">
|
||||
<div class="flex items-center space-x-3">
|
||||
<h3 class="truncate text-sm font-medium text-gray-900">{{ $mod->name }}</h3>
|
||||
<span class="inline-flex flex-shrink-0 items-center rounded-full bg-{{ $mod->spt_version_color_class }}-50 px-1.5 py-0.5 text-xs font-medium text-{{ $mod->spt_version_color_class }}-700 ring-1 ring-inset ring-{{ $mod->spt_version_color_class }}-600/20">{{ $mod->spt_version }}</span>
|
||||
</div>
|
||||
<p class="mt-1 truncate text-sm text-gray-500">{{ $mod->description }}</p>
|
||||
</div>
|
||||
<img class="h-10 w-10 flex-shrink-0 rounded-[5px] bg-gray-300" src="https://placehold.co/300x300/EEE/31343C?font=open-sans&text=MOD" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="-mt-px flex divide-x divide-gray-200">
|
||||
<div class="flex w-0 flex-1">
|
||||
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}" class="relative -mr-px inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-bl-lg border border-transparent py-4 text-sm font-semibold text-gray-900">
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/>
|
||||
</svg>
|
||||
{{ __('View Details') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="-ml-px flex w-0 flex-1">
|
||||
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}/download" class="relative inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-br-lg border border-transparent py-4 text-sm font-semibold text-gray-900">
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9.75v6.75m0 0-3-3m3 3 3-3m-8.25 6a4.5 4.5 0 0 1-1.41-8.775 5.25 5.25 0 0 1 10.233-2.33 3 3 0 0 1 3.758 3.848A3.752 3.752 0 0 1 18 19.5H6.75Z"/>
|
||||
</svg>
|
||||
{{ __('Download') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,16 +1,16 @@
|
||||
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
|
||||
<!-- Primary Navigation Menu -->
|
||||
<nav x-data="{ open: false }" class="bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-700">
|
||||
{{-- Primary Navigation Menu --}}
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex">
|
||||
<!-- Logo -->
|
||||
{{-- Logo --}}
|
||||
<div class="shrink-0 flex items-center">
|
||||
<a href="{{ route('home') }}">
|
||||
<x-application-mark class="block h-9 w-auto"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Links -->
|
||||
{{-- Navigation Links --}}
|
||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||
<x-nav-link href="{{ route('mods') }}" :active="request()->routeIs('mods')">
|
||||
{{ __('Mods') }}
|
||||
@ -19,70 +19,29 @@
|
||||
</div>
|
||||
|
||||
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
||||
<!-- Teams Dropdown -->
|
||||
@if (Laravel\Jetstream\Jetstream::hasTeamFeatures())
|
||||
<div class="ms-3 relative">
|
||||
<x-dropdown align="right" width="60">
|
||||
<x-slot name="trigger">
|
||||
<span class="inline-flex rounded-md">
|
||||
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150">
|
||||
{{ Auth::user()->currentTeam->name }}
|
||||
|
||||
<svg class="ms-2 -me-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="w-60">
|
||||
<!-- Team Management -->
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
{{ __('Manage Team') }}
|
||||
</div>
|
||||
|
||||
<!-- Team Settings -->
|
||||
<x-dropdown-link href="{{ route('teams.show', Auth::user()->currentTeam->id) }}">
|
||||
{{ __('Team Settings') }}
|
||||
</x-dropdown-link>
|
||||
|
||||
@can('create', Laravel\Jetstream\Jetstream::newTeamModel())
|
||||
<x-dropdown-link href="{{ route('teams.create') }}">
|
||||
{{ __('Create New Team') }}
|
||||
</x-dropdown-link>
|
||||
@endcan
|
||||
|
||||
<!-- Team Switcher -->
|
||||
@if (Auth::user()->allTeams()->count() > 1)
|
||||
<div class="border-t border-gray-200"></div>
|
||||
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
{{ __('Switch Teams') }}
|
||||
</div>
|
||||
|
||||
@foreach (Auth::user()->allTeams() as $team)
|
||||
<x-switchable-team :team="$team"/>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-dropdown>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Settings Dropdown -->
|
||||
{{-- Settings Dropdown --}}
|
||||
<div class="ms-3 relative">
|
||||
|
||||
{{-- Theme Toggle Button --}}
|
||||
<button id="theme-toggle" type="button" class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5">
|
||||
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
||||
</svg>
|
||||
<svg id="theme-toggle-light-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" fill-rule="evenodd" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<x-dropdown align="right" width="48">
|
||||
<x-slot name="trigger">
|
||||
@auth()
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
<button class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-gray-300 transition">
|
||||
<button class="flex text-sm border-2 border-transparent dark:border-gray-700 rounded-full focus:outline-none focus:border-gray-300 dark:focus:border-gray-700 transition">
|
||||
<img class="h-8 w-8 rounded-full object-cover" src="{{ Auth::user()->profile_photo_url }}" alt="{{ Auth::user()->name }}"/>
|
||||
</button>
|
||||
@else
|
||||
<span class="inline-flex rounded-md">
|
||||
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150">
|
||||
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-300 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-500 focus:outline-none focus:bg-gray-50 dark:focus:bg-gray-700 active:bg-gray-50 dark:active:bg-gray-700 transition ease-in-out duration-150">
|
||||
{{ Auth::user()->name }}
|
||||
|
||||
<svg class="ms-2 -me-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
@ -95,8 +54,8 @@
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<!-- Account Management -->
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
{{-- Account Management --}}
|
||||
<div class="block px-4 py-2 text-xs text-gray-400 dark:text-gray-300">
|
||||
{{ __('Manage Account') }}
|
||||
</div>
|
||||
|
||||
@ -110,9 +69,9 @@
|
||||
</x-dropdown-link>
|
||||
@endif
|
||||
|
||||
<div class="border-t border-gray-200"></div>
|
||||
<div class="border-t border-gray-200 dark:border-gray-700"></div>
|
||||
|
||||
<!-- Authentication -->
|
||||
{{-- Authentication --}}
|
||||
<form method="POST" action="{{ route('logout') }}" x-data>
|
||||
@csrf
|
||||
|
||||
@ -125,9 +84,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hamburger -->
|
||||
{{-- Hamburger --}}
|
||||
<div class="-me-2 flex items-center sm:hidden">
|
||||
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
|
||||
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 focus:text-gray-500 dark:focus:text-gray-300 transition duration-150 ease-in-out">
|
||||
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
@ -137,7 +96,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Navigation Menu -->
|
||||
{{-- Responsive Navigation Menu --}}
|
||||
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
|
||||
<div class="pt-2 pb-3 space-y-1">
|
||||
<x-responsive-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')">
|
||||
@ -145,8 +104,8 @@
|
||||
</x-responsive-nav-link>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Settings Options -->
|
||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||
{{-- Responsive Settings Options --}}
|
||||
<div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-700">
|
||||
<div class="flex items-center px-4">
|
||||
@auth()
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
@ -156,14 +115,14 @@
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
|
||||
<div class="font-medium text-base text-gray-800 dark:text-gray-300">{{ Auth::user()->name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500 dark:text-gray-300">{{ Auth::user()->email }}</div>
|
||||
</div>
|
||||
@endauth()
|
||||
</div>
|
||||
|
||||
<div class="mt-3 space-y-1">
|
||||
<!-- Account Management -->
|
||||
{{-- Account Management --}}
|
||||
<x-responsive-nav-link href="{{ route('profile.show') }}" :active="request()->routeIs('profile.show')">
|
||||
{{ __('Profile') }}
|
||||
</x-responsive-nav-link>
|
||||
@ -174,7 +133,7 @@
|
||||
</x-responsive-nav-link>
|
||||
@endif
|
||||
|
||||
<!-- Authentication -->
|
||||
{{-- Authentication --}}
|
||||
<form method="POST" action="{{ route('logout') }}" x-data>
|
||||
@csrf
|
||||
|
||||
@ -182,39 +141,6 @@
|
||||
{{ __('Log Out') }}
|
||||
</x-responsive-nav-link>
|
||||
</form>
|
||||
|
||||
<!-- Team Management -->
|
||||
@if (Laravel\Jetstream\Jetstream::hasTeamFeatures())
|
||||
<div class="border-t border-gray-200"></div>
|
||||
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
{{ __('Manage Team') }}
|
||||
</div>
|
||||
|
||||
<!-- Team Settings -->
|
||||
<x-responsive-nav-link href="{{ route('teams.show', Auth::user()->currentTeam->id) }}" :active="request()->routeIs('teams.show')">
|
||||
{{ __('Team Settings') }}
|
||||
</x-responsive-nav-link>
|
||||
|
||||
@can('create', Laravel\Jetstream\Jetstream::newTeamModel())
|
||||
<x-responsive-nav-link href="{{ route('teams.create') }}" :active="request()->routeIs('teams.create')">
|
||||
{{ __('Create New Team') }}
|
||||
</x-responsive-nav-link>
|
||||
@endcan
|
||||
|
||||
<!-- Team Switcher -->
|
||||
@if (Auth::user()->allTeams()->count() > 1)
|
||||
<div class="border-t border-gray-200"></div>
|
||||
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
{{ __('Switch Teams') }}
|
||||
</div>
|
||||
|
||||
@foreach (Auth::user()->allTeams() as $team)
|
||||
<x-switchable-team :team="$team" component="responsive-nav-link"/>
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@ Route::get('/', function () {
|
||||
})->name('home');
|
||||
|
||||
Route::get('/mods', function () {
|
||||
return 'list all mods';
|
||||
return '';
|
||||
})->name('mods');
|
||||
|
||||
Route::middleware(['auth:sanctum', config('jetstream.auth_session'), 'verified'])->group(function () {
|
||||
|
@ -4,6 +4,8 @@ import typography from "@tailwindcss/typography";
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: "selector",
|
||||
|
||||
content: [
|
||||
"./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php",
|
||||
"./vendor/laravel/jetstream/**/*.blade.php",
|
||||
@ -19,11 +21,5 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
safelist: [
|
||||
{
|
||||
pattern: /(bg|text|ring)-(green|yellow|red|grey)-(50|700|600\/20)/,
|
||||
},
|
||||
],
|
||||
|
||||
plugins: [forms, typography],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user