minor fixes
This commit is contained in:
@@ -280,11 +280,18 @@ class BrowseGalleryController extends \App\Http\Controllers\Controller
|
||||
{
|
||||
$primaryCategory = $artwork->categories->sortBy('sort_order')->first();
|
||||
$present = ThumbnailPresenter::present($artwork, 'md');
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$group = $artwork->group;
|
||||
$isGroupPublisher = $group !== null;
|
||||
$avatarUrl = $isGroupPublisher
|
||||
? $group->avatarUrl()
|
||||
: \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$displayName = $isGroupPublisher ? ($group->name ?? 'Skinbase') : ($artwork->user?->name ?? 'Skinbase');
|
||||
$username = $isGroupPublisher ? '' : ($artwork->user?->username ?? '');
|
||||
$profileUrl = $isGroupPublisher ? $group->publicUrl() : ($username !== '' ? '/@' . $username : null);
|
||||
|
||||
return (object) [
|
||||
'id' => $artwork->id,
|
||||
@@ -295,9 +302,18 @@ class BrowseGalleryController extends \App\Http\Controllers\Controller
|
||||
'category_slug' => $primaryCategory->slug ?? '',
|
||||
'thumb_url' => $present['url'],
|
||||
'thumb_srcset' => $present['srcset'] ?? $present['url'],
|
||||
'uname' => $artwork->user?->name ?? 'Skinbase',
|
||||
'username' => $artwork->user?->username ?? '',
|
||||
'uname' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
'published_as_type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'publisher' => [
|
||||
'type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'name' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
],
|
||||
'published_at' => $artwork->published_at,
|
||||
'width' => $artwork->width ?? null,
|
||||
'height' => $artwork->height ?? null,
|
||||
|
||||
@@ -7,7 +7,7 @@ use App\Models\Artwork;
|
||||
use App\Services\CommunityActivityService;
|
||||
use App\Services\ArtworkSearchService;
|
||||
use App\Services\ArtworkService;
|
||||
use App\Services\EarlyGrowth\FeedBlender;
|
||||
use App\Services\EarlyGrowth\AdaptiveTimeWindow;
|
||||
use App\Services\EarlyGrowth\GridFiller;
|
||||
use App\Services\Recommendations\RecommendationFeedResolver;
|
||||
use App\Services\UserSuggestionService;
|
||||
@@ -33,8 +33,8 @@ final class DiscoverController extends Controller
|
||||
public function __construct(
|
||||
private readonly ArtworkService $artworkService,
|
||||
private readonly ArtworkSearchService $searchService,
|
||||
private readonly AdaptiveTimeWindow $timeWindow,
|
||||
private readonly RecommendationFeedResolver $feedResolver,
|
||||
private readonly FeedBlender $feedBlender,
|
||||
private readonly GridFiller $gridFiller,
|
||||
private readonly CommunityActivityService $communityActivity,
|
||||
private readonly UserSuggestionService $userSuggestions,
|
||||
@@ -45,9 +45,18 @@ final class DiscoverController extends Controller
|
||||
public function trending(Request $request)
|
||||
{
|
||||
$perPage = 24;
|
||||
$page = max(1, (int) $request->query('page', 1));
|
||||
$results = $this->searchService->discoverTrending($perPage);
|
||||
$results = $this->gridFiller->fill($results, 0, $page);
|
||||
$windowDays = $this->timeWindow->getTrendingWindowDays(30);
|
||||
|
||||
try {
|
||||
$results = $this->searchService->discoverTrending($perPage);
|
||||
} catch (\Throwable) {
|
||||
$results = $this->fallbackTrendingFromDatabase($perPage, $windowDays);
|
||||
}
|
||||
|
||||
if ($this->paginatorIsEmpty($results)) {
|
||||
$results = $this->fallbackTrendingFromDatabase($perPage, $windowDays);
|
||||
}
|
||||
|
||||
$this->hydrateDiscoverSearchResults($results);
|
||||
|
||||
return view('web.discover.index', [
|
||||
@@ -64,9 +73,22 @@ final class DiscoverController extends Controller
|
||||
public function rising(Request $request)
|
||||
{
|
||||
$perPage = 24;
|
||||
$page = max(1, (int) $request->query('page', 1));
|
||||
$results = $this->searchService->discoverRising($perPage);
|
||||
$results = $this->gridFiller->fill($results, 0, $page);
|
||||
$windowDays = $this->timeWindow->getTrendingWindowDays(30);
|
||||
|
||||
try {
|
||||
$results = $this->searchService->discoverRising($perPage);
|
||||
} catch (\Throwable) {
|
||||
$results = $this->fallbackRisingFromDatabase($perPage, $windowDays);
|
||||
}
|
||||
|
||||
if ($this->paginatorIsEmpty($results)) {
|
||||
$results = $this->fallbackRisingFromDatabase($perPage, $windowDays);
|
||||
}
|
||||
|
||||
if ($this->paginatorHasNoRisingMomentum($results)) {
|
||||
$results = $this->fallbackRisingLowSignalFromDatabase($perPage, $windowDays);
|
||||
}
|
||||
|
||||
$this->hydrateDiscoverSearchResults($results);
|
||||
|
||||
return view('web.discover.index', [
|
||||
@@ -83,11 +105,12 @@ final class DiscoverController extends Controller
|
||||
public function fresh(Request $request)
|
||||
{
|
||||
$perPage = 24;
|
||||
$page = max(1, (int) $request->query('page', 1));
|
||||
$results = $this->searchService->discoverFresh($perPage);
|
||||
// EGS: blend fresh feed with curated + spotlight on page 1
|
||||
$results = $this->feedBlender->blend($results, $perPage, $page);
|
||||
$results = $this->gridFiller->fill($results, 0, $page);
|
||||
|
||||
if ($this->paginatorIsEmpty($results)) {
|
||||
$results = $this->fallbackFreshFromDatabase($perPage);
|
||||
}
|
||||
|
||||
$this->hydrateDiscoverSearchResults($results);
|
||||
|
||||
return view('web.discover.index', [
|
||||
@@ -351,6 +374,152 @@ final class DiscoverController extends Controller
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private function paginatorIsEmpty($paginator): bool
|
||||
{
|
||||
if (! is_object($paginator) || ! method_exists($paginator, 'getCollection')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$items = $paginator->getCollection();
|
||||
|
||||
return ! $items || $items->isEmpty();
|
||||
}
|
||||
|
||||
private function paginatorHasNoRisingMomentum($paginator): bool
|
||||
{
|
||||
if (! is_object($paginator) || ! method_exists($paginator, 'getCollection')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$items = $paginator->getCollection();
|
||||
|
||||
if (! $items || $items->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $items->every(function ($item): bool {
|
||||
$heat = (float) ($item->heat_score ?? $item->stats?->heat_score ?? 0);
|
||||
$velocity = (float) ($item->engagement_velocity ?? $item->stats?->engagement_velocity ?? 0);
|
||||
|
||||
return $heat <= 0.0 && $velocity <= 0.0;
|
||||
});
|
||||
}
|
||||
|
||||
private function fallbackFreshFromDatabase(int $perPage)
|
||||
{
|
||||
return Artwork::query()
|
||||
->public()
|
||||
->published()
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
'user.profile:user_id,avatar_hash',
|
||||
'categories:id,name,slug,content_type_id,parent_id,sort_order',
|
||||
'categories.contentType:id,slug,name',
|
||||
])
|
||||
->orderByDesc('published_at')
|
||||
->orderByDesc('id')
|
||||
->paginate($perPage)
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
private function fallbackTrendingFromDatabase(int $perPage, int $windowDays)
|
||||
{
|
||||
$cutoff = now()->subDays($windowDays)->startOfDay();
|
||||
|
||||
return Artwork::query()
|
||||
->public()
|
||||
->published()
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
'user.profile:user_id,avatar_hash',
|
||||
'categories:id,name,slug,content_type_id,parent_id,sort_order',
|
||||
'categories.contentType:id,slug,name',
|
||||
])
|
||||
->leftJoin('artwork_stats as discover_stats', 'discover_stats.artwork_id', '=', 'artworks.id')
|
||||
->select('artworks.*')
|
||||
->where('artworks.published_at', '>=', $cutoff)
|
||||
->orderByDesc('discover_stats.ranking_score')
|
||||
->orderByDesc('discover_stats.engagement_velocity')
|
||||
->orderByDesc('discover_stats.views')
|
||||
->orderByDesc('artworks.published_at')
|
||||
->orderByDesc('artworks.id')
|
||||
->paginate($perPage)
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
private function fallbackRisingFromDatabase(int $perPage, int $windowDays)
|
||||
{
|
||||
$cutoff = now()->subDays($windowDays)->startOfDay();
|
||||
|
||||
return Artwork::query()
|
||||
->public()
|
||||
->published()
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
'user.profile:user_id,avatar_hash',
|
||||
'categories:id,name,slug,content_type_id,parent_id,sort_order',
|
||||
'categories.contentType:id,slug,name',
|
||||
])
|
||||
->leftJoin('artwork_stats as discover_stats', 'discover_stats.artwork_id', '=', 'artworks.id')
|
||||
->select('artworks.*')
|
||||
->selectRaw('COALESCE(discover_stats.heat_score, 0) as heat_score')
|
||||
->selectRaw('COALESCE(discover_stats.engagement_velocity, 0) as engagement_velocity')
|
||||
->where('artworks.published_at', '>=', $cutoff)
|
||||
->orderByDesc('discover_stats.heat_score')
|
||||
->orderByDesc('discover_stats.engagement_velocity')
|
||||
->orderByDesc('artworks.published_at')
|
||||
->orderByDesc('artworks.id')
|
||||
->paginate($perPage)
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
private function fallbackRisingLowSignalFromDatabase(int $perPage, int $windowDays)
|
||||
{
|
||||
$cutoff = now()->subDays($windowDays)->startOfDay();
|
||||
$recentActivity = $this->risingRecentActivitySubquery();
|
||||
|
||||
return Artwork::query()
|
||||
->public()
|
||||
->published()
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
'user.profile:user_id,avatar_hash',
|
||||
'categories:id,name,slug,content_type_id,parent_id,sort_order',
|
||||
'categories.contentType:id,slug,name',
|
||||
])
|
||||
->leftJoin('artwork_stats as discover_stats', 'discover_stats.artwork_id', '=', 'artworks.id')
|
||||
->leftJoinSub($recentActivity, 'recent_rising_activity', function ($join): void {
|
||||
$join->on('recent_rising_activity.artwork_id', '=', 'artworks.id');
|
||||
})
|
||||
->select('artworks.*')
|
||||
->selectRaw('COALESCE(discover_stats.heat_score, 0) as heat_score')
|
||||
->selectRaw('COALESCE(discover_stats.engagement_velocity, 0) as engagement_velocity')
|
||||
->selectRaw('COALESCE(recent_rising_activity.recent_signal_24h, 0) as recent_signal_24h')
|
||||
->where('artworks.published_at', '>=', $cutoff)
|
||||
->orderByDesc('recent_signal_24h')
|
||||
->orderByDesc('artworks.published_at')
|
||||
->orderByDesc('artworks.id')
|
||||
->paginate($perPage)
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
private function risingRecentActivitySubquery()
|
||||
{
|
||||
$since = now()->startOfHour()->subHours(24);
|
||||
|
||||
return DB::table('artwork_metric_snapshots_hourly as rising_snapshots')
|
||||
->selectRaw('rising_snapshots.artwork_id')
|
||||
->selectRaw('(
|
||||
COALESCE(MAX(rising_snapshots.views_count) - MIN(rising_snapshots.views_count), 0)
|
||||
+ (COALESCE(MAX(rising_snapshots.downloads_count) - MIN(rising_snapshots.downloads_count), 0) * 3)
|
||||
+ (COALESCE(MAX(rising_snapshots.favourites_count) - MIN(rising_snapshots.favourites_count), 0) * 4)
|
||||
+ (COALESCE(MAX(rising_snapshots.comments_count) - MIN(rising_snapshots.comments_count), 0) * 5)
|
||||
+ (COALESCE(MAX(rising_snapshots.shares_count) - MIN(rising_snapshots.shares_count), 0) * 6)
|
||||
) as recent_signal_24h')
|
||||
->where('rising_snapshots.bucket_hour', '>=', $since)
|
||||
->groupBy('rising_snapshots.artwork_id');
|
||||
}
|
||||
|
||||
private function hydrateDiscoverSearchResults($paginator): void
|
||||
{
|
||||
if (!is_object($paginator) || !method_exists($paginator, 'getCollection') || !method_exists($paginator, 'setCollection')) {
|
||||
@@ -377,6 +546,7 @@ final class DiscoverController extends Controller
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
'user.profile:user_id,avatar_hash',
|
||||
'group:id,name,slug,avatar_path',
|
||||
'categories:id,name,slug,content_type_id,parent_id,sort_order',
|
||||
])
|
||||
->get()
|
||||
@@ -398,9 +568,12 @@ final class DiscoverController extends Controller
|
||||
'category_slug' => $item->category_slug ?? '',
|
||||
'thumb_url' => $item->thumbnail_url ?? $item->thumb_url ?? $item->thumb ?? null,
|
||||
'thumb_srcset' => $item->thumb_srcset ?? null,
|
||||
'uname' => $item->author ?? $item->uname ?? 'Skinbase',
|
||||
'username' => $item->username ?? '',
|
||||
'uname' => $item->author_name ?? $item->author ?? $item->uname ?? 'Skinbase',
|
||||
'username' => (($item->published_as_type ?? null) === 'group') ? '' : ($item->username ?? ''),
|
||||
'avatar_url' => \App\Support\AvatarUrl::forUser((int) ($item->user_id ?? $item->author_id ?? 0), null, 64),
|
||||
'profile_url' => $item->profile_url ?? null,
|
||||
'published_as_type' => $item->published_as_type ?? null,
|
||||
'publisher' => $item->publisher ?? null,
|
||||
'published_at' => $item->published_at ?? null,
|
||||
'width' => isset($item->width) && $item->width ? (int) $item->width : null,
|
||||
'height' => isset($item->height) && $item->height ? (int) $item->height : null,
|
||||
@@ -413,11 +586,18 @@ final class DiscoverController extends Controller
|
||||
{
|
||||
$primaryCategory = $artwork->categories->sortBy('sort_order')->first();
|
||||
$present = ThumbnailPresenter::present($artwork, 'md');
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$group = $artwork->group;
|
||||
$isGroupPublisher = $group !== null;
|
||||
$avatarUrl = $isGroupPublisher
|
||||
? $group->avatarUrl()
|
||||
: \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$displayName = $isGroupPublisher ? ($group->name ?? 'Skinbase') : ($artwork->user?->name ?? 'Skinbase');
|
||||
$username = $isGroupPublisher ? '' : ($artwork->user?->username ?? '');
|
||||
$profileUrl = $isGroupPublisher ? $group->publicUrl() : ($username !== '' ? '/@' . $username : null);
|
||||
|
||||
return (object) [
|
||||
'id' => $artwork->id,
|
||||
@@ -429,8 +609,18 @@ final class DiscoverController extends Controller
|
||||
'gid_num' => $primaryCategory ? ((int) $primaryCategory->id % 5) * 5 : 0,
|
||||
'thumb_url' => $present['url'],
|
||||
'thumb_srcset' => $present['srcset'] ?? $present['url'],
|
||||
'uname' => $artwork->user->name ?? 'Skinbase',
|
||||
'uname' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
'published_as_type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'publisher' => [
|
||||
'type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'name' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
],
|
||||
'published_at' => $artwork->published_at,
|
||||
'width' => $artwork->width ?? null,
|
||||
'height' => $artwork->height ?? null,
|
||||
|
||||
@@ -276,11 +276,18 @@ final class ExploreController extends Controller
|
||||
{
|
||||
$primary = $artwork->categories->sortBy('sort_order')->first();
|
||||
$present = ThumbnailPresenter::present($artwork, 'md');
|
||||
$avatarUrl = \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$group = $artwork->group;
|
||||
$isGroupPublisher = $group !== null;
|
||||
$avatarUrl = $isGroupPublisher
|
||||
? $group->avatarUrl()
|
||||
: \App\Support\AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$displayName = $isGroupPublisher ? ($group->name ?? 'Skinbase') : ($artwork->user?->name ?? 'Skinbase');
|
||||
$username = $isGroupPublisher ? '' : ($artwork->user?->username ?? '');
|
||||
$profileUrl = $isGroupPublisher ? $group->publicUrl() : ($username !== '' ? '/@' . $username : null);
|
||||
|
||||
return (object) [
|
||||
'id' => $artwork->id,
|
||||
@@ -291,9 +298,18 @@ final class ExploreController extends Controller
|
||||
'category_slug' => $primary->slug ?? '',
|
||||
'thumb_url' => $present['url'],
|
||||
'thumb_srcset' => $present['srcset'] ?? $present['url'],
|
||||
'uname' => $artwork->user?->name ?? 'Skinbase',
|
||||
'username' => $artwork->user?->username ?? '',
|
||||
'uname' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
'published_as_type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'publisher' => [
|
||||
'type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'name' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
],
|
||||
'published_at' => $artwork->published_at,
|
||||
'slug' => $artwork->slug ?? '',
|
||||
'width' => $artwork->width ?? null,
|
||||
|
||||
@@ -290,11 +290,18 @@ final class SimilarArtworksPageController extends Controller
|
||||
{
|
||||
$primary = $artwork->categories->sortBy('sort_order')->first();
|
||||
$present = ThumbnailPresenter::present($artwork, 'md');
|
||||
$avatarUrl = AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$group = $artwork->group;
|
||||
$isGroupPublisher = $group !== null;
|
||||
$avatarUrl = $isGroupPublisher
|
||||
? $group->avatarUrl()
|
||||
: AvatarUrl::forUser(
|
||||
(int) ($artwork->user_id ?? 0),
|
||||
$artwork->user?->profile?->avatar_hash ?? null,
|
||||
64
|
||||
);
|
||||
$displayName = $isGroupPublisher ? ($group->name ?? 'Skinbase') : ($artwork->user?->name ?? 'Skinbase');
|
||||
$username = $isGroupPublisher ? '' : ($artwork->user?->username ?? '');
|
||||
$profileUrl = $isGroupPublisher ? $group->publicUrl() : ($username !== '' ? '/@' . $username : null);
|
||||
|
||||
return (object) [
|
||||
'id' => $artwork->id,
|
||||
@@ -305,9 +312,18 @@ final class SimilarArtworksPageController extends Controller
|
||||
'category_slug' => $primary?->slug ?? '',
|
||||
'thumb_url' => $present['url'],
|
||||
'thumb_srcset' => $present['srcset'] ?? $present['url'],
|
||||
'uname' => $artwork->user?->name ?? 'Skinbase',
|
||||
'username' => $artwork->user?->username ?? '',
|
||||
'uname' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
'published_as_type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'publisher' => [
|
||||
'type' => $isGroupPublisher ? 'group' : 'user',
|
||||
'name' => $displayName,
|
||||
'username' => $username,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'profile_url' => $profileUrl,
|
||||
],
|
||||
'published_at' => $artwork->published_at,
|
||||
'slug' => $artwork->slug ?? '',
|
||||
'width' => $artwork->width ?? null,
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\ContentType;
|
||||
use App\Models\Tag;
|
||||
use App\Services\ArtworkSearchService;
|
||||
use App\Services\EarlyGrowth\GridFiller;
|
||||
use App\Services\Tags\TagDiscoveryService;
|
||||
use App\Services\ThumbnailPresenter;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -18,7 +17,6 @@ final class TagController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ArtworkSearchService $search,
|
||||
private readonly GridFiller $gridFiller,
|
||||
private readonly TagDiscoveryService $tagDiscovery,
|
||||
) {}
|
||||
|
||||
@@ -45,29 +43,10 @@ final class TagController extends Controller
|
||||
|
||||
public function show(Tag $tag, Request $request): View
|
||||
{
|
||||
$sort = $request->query('sort', 'popular'); // popular | latest | downloads
|
||||
$sort = $request->query('sort', 'popular'); // popular | likes | latest | downloads
|
||||
$perPage = min((int) $request->query('per_page', 24), 100);
|
||||
|
||||
// Convert sort param to Meili sort expression
|
||||
$sortMap = [
|
||||
'popular' => 'views:desc',
|
||||
'likes' => 'likes:desc',
|
||||
'latest' => 'created_at:desc',
|
||||
'downloads' => 'downloads:desc',
|
||||
];
|
||||
$meiliSort = $sortMap[$sort] ?? 'views:desc';
|
||||
|
||||
$artworks = \App\Models\Artwork::search('')
|
||||
->options([
|
||||
'filter' => 'is_public = true AND is_approved = true AND tags = "' . addslashes($tag->slug) . '"',
|
||||
'sort' => [$meiliSort],
|
||||
])
|
||||
->paginate($perPage)
|
||||
->appends(['sort' => $sort]);
|
||||
|
||||
// EGS: ensure tag pages never show a half-empty grid on page 1
|
||||
$page = max(1, (int) $request->query('page', 1));
|
||||
$artworks = $this->gridFiller->fill($artworks, 0, $page);
|
||||
$artworks = $this->search->byTag($tag->slug, $perPage, $sort);
|
||||
|
||||
// Eager-load relations used by the gallery presenter and thumbnails.
|
||||
$artworks->getCollection()->each(fn($m) => $m->loadMissing(['user.profile', 'categories']));
|
||||
|
||||
Reference in New Issue
Block a user