Merge remote-tracking branch 'upstream/develop' into update-mod-list-stats

This commit is contained in:
IsWaffle 2024-09-11 14:38:32 -04:00
commit 0190e0431d
15 changed files with 305 additions and 399 deletions

10
.github/README.md vendored
View File

@ -12,7 +12,7 @@ The Forge is a Laravel-based web application that provides a platform for the Si
## Development Environment Setup ## Development Environment Setup
We use [Laravel Sail](https://laravel.com/docs/11.x/sail) to mirror the services that are used in our production server in a local development environment. You can see detailed instructions on how to configure the [full development environment](https://github.com/sp-tarkov/forge/wiki/Full-Windows-Dev-Env) or a [lightweight development environment](https://github.com/sp-tarkov/forge/wiki/Light-Windows-Dev-Env) on the project wiki. The full development environment is recommended. We use [Laravel Sail](https://laravel.com/docs/11.x/sail) to mirror the services that are used in our production server in a local development environment. You can see detailed instructions on how to configure the [full development environment](https://dev.sp-tarkov.com/SPT/forge/wiki/Full-Windows-Dev-Env) or a [lightweight development environment](https://dev.sp-tarkov.com/SPT/forge/wiki/Light-Windows-Dev-Env) on the project wiki. The full development environment is recommended.
### Available Services: ### Available Services:
@ -26,7 +26,7 @@ We use [Laravel Sail](https://laravel.com/docs/11.x/sail) to mirror the services
### Notable Routes ### Notable Routes
| Service | Authentication | Access Via Host | | Service | Authentication | Access Via Host |
|----------------------------------|----------------|-----------------------------| |----------------------------------|----------------|----------------------------|
| Laravel Filament Admin Panel | Via User Role | <http://localhost/admin> | | Laravel Filament Admin Panel | Via User Role | <http://localhost/admin> |
| Redis Queue Management (Horizon) | Via User Role | <http://localhost/horizon> | | Redis Queue Management (Horizon) | Via User Role | <http://localhost/horizon> |
| Website Status (Pulse) | Via User Role | <http://localhost/pulse> | | Website Status (Pulse) | Via User Role | <http://localhost/pulse> |
@ -80,12 +80,12 @@ For more information on Laravel development, please refer to the [official docum
## Development Discussion ## Development Discussion
*__Please note__, we are very early in development and will likely not accept work that is not discussed beforehand through the following channels...* *__Please note__, we are very early in development and will likely not accept work that is not discussed beforehand.*
You may propose new features or improvements of existing Forge behavior in [the repository's GitHub discussion board](https://github.com/sp-tarkov/forge/discussions). If you propose a new feature, please be willing to implement at least some of the code that would be needed to complete the feature.
Informal discussion regarding bugs, new features, and implementation of existing features takes place in the `#website-general` channel of the [Single Player Tarkov Discord server](https://discord.com/invite/Xn9msqQZan). Refringe, the maintainer of Forge, is typically present in the channel on weekdays from 9am-5pm Eastern Time (ET), and sporadically present in the channel at other times. Informal discussion regarding bugs, new features, and implementation of existing features takes place in the `#website-general` channel of the [Single Player Tarkov Discord server](https://discord.com/invite/Xn9msqQZan). Refringe, the maintainer of Forge, is typically present in the channel on weekdays from 9am-5pm Eastern Time (ET), and sporadically present in the channel at other times.
If you propose a new feature, please be willing to implement at least some of the code that would be needed to complete the feature.
## Which Branch? ## Which Branch?
The `main` branch is the default branch for Forge. This branch is used for the latest stable release of the site. The `develop` branch is used for the latest development changes. All feature branches should be based on the `develop` branch. All pull requests should target the `develop` branch. The `main` branch is the default branch for Forge. This branch is used for the latest stable release of the site. The `develop` branch is used for the latest development changes. All feature branches should be based on the `develop` branch. All pull requests should target the `develop` branch.

View File

@ -8,7 +8,6 @@ use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Livewire\Attributes\Computed; use Livewire\Attributes\Computed;
use Livewire\Attributes\Session;
use Livewire\Attributes\Url; use Livewire\Attributes\Url;
use Livewire\Component; use Livewire\Component;
use Livewire\WithPagination; use Livewire\WithPagination;
@ -21,41 +20,37 @@ class Index extends Component
* The search query value. * The search query value.
*/ */
#[Url] #[Url]
#[Session]
public string $query = ''; public string $query = '';
/** /**
* The sort order value. * The sort order value.
*/ */
#[Url] #[Url]
#[Session]
public string $order = 'created'; public string $order = 'created';
/** /**
* The SPT versions filter value. * The SPT versions filter value.
*/ */
#[Url] #[Url]
#[Session]
public array $sptVersions = []; public array $sptVersions = [];
/** /**
* The featured filter value. * The featured filter value.
*/ */
#[Url] #[Url]
#[Session]
public string $featured = 'include'; public string $featured = 'include';
/** /**
* The available SPT versions. * The available SPT versions.
*/ */
public Collection $availableSptVersions; public Collection $activeSptVersions;
/** /**
* The component mount method, run only once when the component is mounted. * The component mount method, run only once when the component is mounted.
*/ */
public function mount(): void public function mount(): void
{ {
$this->availableSptVersions = $this->availableSptVersions ?? Cache::remember('available-spt-versions', 60 * 60, function () { $this->activeSptVersions = $this->activeSptVersions ?? Cache::remember('active-spt-versions', 60 * 60, function () {
return SptVersion::getVersionsForLastThreeMinors(); return SptVersion::getVersionsForLastThreeMinors();
}); });
@ -67,7 +62,7 @@ class Index extends Component
*/ */
public function getLatestMinorVersions(): Collection public function getLatestMinorVersions(): Collection
{ {
return $this->availableSptVersions->filter(function (SptVersion $sptVersion) { return $this->activeSptVersions->filter(function (SptVersion $sptVersion) {
return $sptVersion->isLatestMinor(); return $sptVersion->isLatestMinor();
}); });
} }
@ -102,9 +97,6 @@ class Index extends Component
$this->query = ''; $this->query = '';
$this->sptVersions = $this->getLatestMinorVersions()->pluck('version')->toArray(); $this->sptVersions = $this->getLatestMinorVersions()->pluck('version')->toArray();
$this->featured = 'include'; $this->featured = 'include';
// Clear local storage
$this->dispatch('clear-filters');
} }
/** /**

View File

@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Laravel\Scout\Searchable; use Laravel\Scout\Searchable;
@ -144,6 +145,14 @@ class Mod extends Model
return false; return false;
} }
// Ensure the latest SPT version is within the last three minor versions.
$activeSptVersions = Cache::remember('active-spt-versions', 60 * 60, function () {
return SptVersion::getVersionsForLastThreeMinors();
});
if (! in_array($latestVersion->latestSptVersion()->first()->version, $activeSptVersions->pluck('version')->toArray())) {
return false;
}
// All conditions are met; the mod should be searchable. // All conditions are met; the mod should be searchable.
return true; return true;
} }

View File

@ -11,8 +11,8 @@ use App\Observers\ModDependencyObserver;
use App\Observers\ModObserver; use App\Observers\ModObserver;
use App\Observers\ModVersionObserver; use App\Observers\ModVersionObserver;
use App\Observers\SptVersionObserver; use App\Observers\SptVersionObserver;
use App\Services\LatestSptVersionService;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Number; use Illuminate\Support\Number;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@ -24,9 +24,7 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register(): void public function register(): void
{ {
$this->app->singleton(LatestSptVersionService::class, function ($app) { //
return new LatestSptVersionService;
});
} }
/** /**
@ -37,18 +35,34 @@ class AppServiceProvider extends ServiceProvider
// Allow mass assignment for all models. Be careful! // Allow mass assignment for all models. Be careful!
Model::unguard(); Model::unguard();
// Register observers. $this->registerObservers();
Mod::observe(ModObserver::class);
ModVersion::observe(ModVersionObserver::class); $this->registerNumberMacros();
ModDependency::observe(ModDependencyObserver::class); $this->registerCarbonMacros();
SptVersion::observe(SptVersionObserver::class);
// This gate determines who can access the Pulse dashboard. // This gate determines who can access the Pulse dashboard.
Gate::define('viewPulse', function (User $user) { Gate::define('viewPulse', function (User $user) {
return $user->isAdmin(); return $user->isAdmin();
}); });
}
// Register a number macro to format download numbers. /**
* Register model observers.
*/
private function registerObservers(): void
{
Mod::observe(ModObserver::class);
ModVersion::observe(ModVersionObserver::class);
ModDependency::observe(ModDependencyObserver::class);
SptVersion::observe(SptVersionObserver::class);
}
/**
* Register custom number macros.
*/
private function registerNumberMacros(): void
{
// Format download numbers.
Number::macro('downloads', function (int|float $number) { Number::macro('downloads', function (int|float $number) {
return Number::forHumans( return Number::forHumans(
$number, $number,
@ -58,4 +72,22 @@ class AppServiceProvider extends ServiceProvider
); );
}); });
} }
/**
* Register custom Carbon macros.
*/
private function registerCarbonMacros(): void
{
// Format dates dynamically based on the time passed.
Carbon::macro('dynamicFormat', function (Carbon $date) {
if ($date->diff(now())->m > 1) {
return $date->format('M jS, Y');
}
if ($date->diff(now())->d === 0) {
return $date->diffForHumans();
}
return $date->format('M jS, g:i A');
});
}
} }

View File

@ -88,16 +88,19 @@ class ModListSection extends Component
'title' => __('Featured Mods'), 'title' => __('Featured Mods'),
'mods' => $this->modsFeatured, 'mods' => $this->modsFeatured,
'versionScope' => 'latestVersion', 'versionScope' => 'latestVersion',
'link' => '/mods?featured=only',
], ],
[ [
'title' => __('Newest Mods'), 'title' => __('Newest Mods'),
'mods' => $this->modsLatest, 'mods' => $this->modsLatest,
'versionScope' => 'latestVersion', 'versionScope' => 'latestVersion',
'link' => '/mods',
], ],
[ [
'title' => __('Recently Updated Mods'), 'title' => __('Recently Updated Mods'),
'mods' => $this->modsUpdated, 'mods' => $this->modsUpdated,
'versionScope' => 'lastUpdatedVersion', 'versionScope' => 'lastUpdatedVersion',
'link' => '/mods?order=updated',
], ],
]; ];
} }

View File

@ -24,4 +24,5 @@ return Application::configure(basePath: dirname(__DIR__))
}) })
->withExceptions(function (Exceptions $exceptions) { ->withExceptions(function (Exceptions $exceptions) {
// //
})->create(); })
->create();

View File

@ -36,7 +36,6 @@
"mockery/mockery": "^1.6", "mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.1", "nunomaduro/collision": "^8.1",
"pestphp/pest": "^2.34", "pestphp/pest": "^2.34",
"pestphp/pest-plugin-stressless": "^2.2",
"spatie/laravel-ignition": "^2.8" "spatie/laravel-ignition": "^2.8"
}, },
"autoload": { "autoload": {

498
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
<?php <?php
use Illuminate\Support\Facades\Facade;
return [ return [
/* /*
@ -123,4 +125,19 @@ return [
'store' => env('APP_MAINTENANCE_STORE', 'database'), 'store' => env('APP_MAINTENANCE_STORE', 'database'),
], ],
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => Facade::defaultAliases()->merge([
'Carbon' => \Carbon\Carbon::class,
])->toArray(),
]; ];

64
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "html", "name": "forge",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
@ -780,9 +780,9 @@
] ]
}, },
"node_modules/@tailwindcss/forms": { "node_modules/@tailwindcss/forms": {
"version": "0.5.8", "version": "0.5.9",
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.8.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz",
"integrity": "sha512-DJs7B7NPD0JH7BVvdHWNviWmunlFhuEkz7FyFxE4japOWYMLl9b1D6+Z9mivJJPWr6AEbmlPqgiFRyLwFB1SgQ==", "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -915,9 +915,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.7.6", "version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.6.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-Ekur6XDwhnJ5RgOCaxFnXyqlPALI3rVeukZMwOdfghW7/wGz784BYKiQq+QD8NPcr91KRo30KfHOchyijwWw7g==", "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1013,9 +1013,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001655", "version": "1.0.30001658",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001658.tgz",
"integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==", "integrity": "sha512-N2YVqWbJELVdrnsW5p+apoQyYt51aBMSsBZki1XZEfeBCexcM/sf4xiAHcXQBkuOwJBXtWF7aW1sYX6tKebPHw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -1161,9 +1161,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.13", "version": "1.5.18",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz",
"integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "integrity": "sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -1273,9 +1273,9 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.6", "version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -1784,9 +1784,9 @@
} }
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.1", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -1824,9 +1824,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.41", "version": "8.4.45",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz",
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -2272,9 +2272,9 @@
} }
}, },
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"engines": { "engines": {
@ -2574,14 +2574,14 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.2", "version": "5.4.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz",
"integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", "integrity": "sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.41", "postcss": "^8.4.43",
"rollup": "^4.20.0" "rollup": "^4.20.0"
}, },
"bin": { "bin": {
@ -2759,9 +2759,9 @@
} }
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.5.0", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
"integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {

View File

@ -1,4 +1,4 @@
@props(['mod', 'versionScope' => 'latestVersion']) @props(['mod', 'versionScope' => 'none'])
<a href="/mod/{{ $mod->id }}/{{ $mod->slug }}" class="mod-list-component relative mx-auto w-full max-w-md md:max-w-2xl"> <a href="/mod/{{ $mod->id }}/{{ $mod->slug }}" class="mod-list-component relative mx-auto w-full max-w-md md:max-w-2xl">
@if ($mod->featured && !request()->routeIs('home')) @if ($mod->featured && !request()->routeIs('home'))
@ -18,16 +18,20 @@
<div class="pb-3"> <div class="pb-3">
<div class="flex justify-between items-center space-x-3"> <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> <h3 class="block mt-1 text-lg leading-tight font-medium text-black dark:text-white group-hover:underline">{{ $mod->name }}</h3>
@if($versionScope !== 'none' && $mod->{$versionScope} !== null && $mod->{$versionScope}->latestSptVersion !== null)
<span class="badge-version {{ $mod->{$versionScope}->latestSptVersion->first()->color_class }} inline-flex items-center rounded-md px-2 py-1 text-xs font-medium text-nowrap"> <span class="badge-version {{ $mod->{$versionScope}->latestSptVersion->first()->color_class }} inline-flex items-center rounded-md px-2 py-1 text-xs font-medium text-nowrap">
{{ $mod->{$versionScope}->latestSptVersion->first()->version_formatted }} {{ $mod->{$versionScope}->latestSptVersion->first()->version_formatted }}
</span> </span>
@endif
</div> </div>
<p class="text-sm italic text-slate-600 dark:text-gray-200"> <p class="text-sm italic text-slate-600 dark:text-gray-200">
By {{ $mod->users->pluck('name')->implode(', ') }} By {{ $mod->users->pluck('name')->implode(', ') }}
</p> </p>
<p class="mt-2 text-slate-500 dark:text-gray-300">{{ Str::limit($mod->teaser, 100) }}</p> <p class="mt-2 text-slate-500 dark:text-gray-300">{{ Str::limit($mod->teaser, 100) }}</p>
</div> </div>
@if($versionScope !== 'none' && $mod->{$versionScope} !== null)
<x-mod-list-stats :mod="$mod" :modVersion="$mod->{$versionScope}"/> <x-mod-list-stats :mod="$mod" :modVersion="$mod->{$versionScope}"/>
@endif
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,10 +1,6 @@
@props(['mods', 'versionScope', 'title']) @props(['mods', 'versionScope', 'title', 'link'])
<div class="mx-auto max-w-7xl px-4 pt-16 sm:px-6 lg:px-8"> <div class="mx-auto max-w-7xl px-4 pt-16 sm:px-6 lg:px-8">
{{-- <x-page-content-title :title="$title" button-text="View All" :button-link="$link" />
TODO: The button-link should be dynamic based on the versionScope. Eg. Featured `View All` button should take
the user to the mods page with the `featured` query parameter set.
--}}
<x-page-content-title :title="$title" button-text="View All" button-link="/mods" />
<x-mod-list :mods="$mods" :versionScope="$versionScope" /> <x-mod-list :mods="$mods" :versionScope="$versionScope" />
</div> </div>

View File

@ -3,5 +3,6 @@
'title' => $section['title'], 'title' => $section['title'],
'mods' => $section['mods'], 'mods' => $section['mods'],
'versionScope' => $section['versionScope'], 'versionScope' => $section['versionScope'],
'link' => $section['link']
]) ])
@endforeach @endforeach

View File

@ -53,13 +53,13 @@
<div class="mx-auto grid max-w-7xl grid-cols-2 gap-x-4 px-4 text-sm sm:px-6 md:gap-x-6 lg:px-8"> <div class="mx-auto grid max-w-7xl grid-cols-2 gap-x-4 px-4 text-sm sm:px-6 md:gap-x-6 lg:px-8">
<div class="grid auto-rows-min grid-cols-1 gap-y-10 md:grid-cols-2 md:gap-x-6"> <div class="grid auto-rows-min grid-cols-1 gap-y-10 md:grid-cols-2 md:gap-x-6">
@php @php
$totalVersions = count($availableSptVersions); $totalVersions = count($activeSptVersions);
$half = ceil($totalVersions / 2); $half = ceil($totalVersions / 2);
@endphp @endphp
<fieldset> <fieldset>
<legend class="block font-medium text-gray-900 dark:text-gray-100">{{ __('SPT Versions') }}</legend> <legend class="block font-medium text-gray-900 dark:text-gray-100">{{ __('SPT Versions') }}</legend>
<div class="space-y-6 pt-6 sm:space-y-4 sm:pt-4"> <div class="space-y-6 pt-6 sm:space-y-4 sm:pt-4">
@foreach ($availableSptVersions as $index => $version) @foreach ($activeSptVersions as $index => $version)
@if ($index < $half) @if ($index < $half)
<x-filter-checkbox id="sptVersions-{{ $index }}" name="sptVersions" value="{{ $version->version }}">{{ $version->version }}</x-filter-checkbox> <x-filter-checkbox id="sptVersions-{{ $index }}" name="sptVersions" value="{{ $version->version }}">{{ $version->version }}</x-filter-checkbox>
@endif @endif
@ -69,7 +69,7 @@
<fieldset> <fieldset>
<legend class="block font-medium text-gray-900 dark:text-gray-100">&nbsp;</legend> <legend class="block font-medium text-gray-900 dark:text-gray-100">&nbsp;</legend>
<div class="space-y-6 pt-6 sm:space-y-4 sm:pt-4"> <div class="space-y-6 pt-6 sm:space-y-4 sm:pt-4">
@foreach ($availableSptVersions as $index => $version) @foreach ($activeSptVersions as $index => $version)
@if ($index >= $half) @if ($index >= $half)
<x-filter-checkbox id="sptVersions-{{ $index }}" name="sptVersions" value="{{ $version->version }}">{{ $version->version }}</x-filter-checkbox> <x-filter-checkbox id="sptVersions-{{ $index }}" name="sptVersions" value="{{ $version->version }}">{{ $version->version }}</x-filter-checkbox>
@endif @endif

View File

@ -114,8 +114,8 @@
<a href="{{ $version->virus_total_link }}">{{__('Virus Total Results')}}</a> <a href="{{ $version->virus_total_link }}">{{__('Virus Total Results')}}</a>
</div> </div>
<div class="flex items-center justify-between text-gray-600 dark:text-gray-400"> <div class="flex items-center justify-between text-gray-600 dark:text-gray-400">
<span>{{ __('Created') }} {{ $version->created_at->format("M d, h:m a") }}</span> <span>{{ __('Created') }} {{ Carbon::dynamicFormat($version->created_at) }}</span>
<span>{{ __('Updated') }} {{ $version->updated_at->format("M d, h:m a") }}</span> <span>{{ __('Updated') }} {{ Carbon::dynamicFormat($version->updated_at) }}</span>
</div> </div>
{{-- Display latest resolved dependencies --}} {{-- Display latest resolved dependencies --}}